Exemple #1
0
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__log(apr_getopt_t *os,
            void *baton,
            apr_pool_t *pool)
{
  svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
  svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
  apr_array_header_t *targets;
  struct log_receiver_baton lb;
  const char *target;
  int i;
  svn_opt_revision_t peg_revision;
  const char *true_path;
  apr_array_header_t *revprops;

  if (!opt_state->xml)
    {
      if (opt_state->all_revprops)
        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                _("'with-all-revprops' option only valid in"
                                  " XML mode"));
      if (opt_state->revprop_table != NULL)
        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                _("'with-revprop' option only valid in"
                                  " XML mode"));
    }

  SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
                                                      opt_state->targets, 
                                                      pool));

  /* Add "." if user passed 0 arguments */
  svn_opt_push_implicit_dot_target(targets, pool);

  target = APR_ARRAY_IDX(targets, 0, const char *);

  /* Determine if they really want a two-revision range. */
  if (opt_state->used_change_arg)
    {
      if (opt_state->start_revision.value.number < 
          opt_state->end_revision.value.number)
        opt_state->start_revision = opt_state->end_revision;
      else
        opt_state->end_revision = opt_state->start_revision;
    }

  /* Strip peg revision if targets contains an URI. */
  SVN_ERR(svn_opt_parse_path(&peg_revision, &true_path, target, pool));
  APR_ARRAY_IDX(targets, 0, const char *) = true_path;

  if ((opt_state->start_revision.kind != svn_opt_revision_unspecified)
      && (opt_state->end_revision.kind == svn_opt_revision_unspecified))
    {
      /* If the user specified exactly one revision, then start rev is
         set but end is not.  We show the log message for just that
         revision by making end equal to start.

         Note that if the user requested a single dated revision, then
         this will cause the same date to be resolved twice.  The
         extra code complexity to get around this slight inefficiency
         doesn't seem worth it, however.  */

      opt_state->end_revision = opt_state->start_revision;
    }
  else if (opt_state->start_revision.kind == svn_opt_revision_unspecified)
    {
      /* Default to any specified peg revision.  Otherwise, if the
         first target is an URL, then we default to HEAD:0.  Lastly,
         the default is BASE:0 since WC@HEAD may not exist. */
      if (peg_revision.kind == svn_opt_revision_unspecified)
        {
          if (svn_path_is_url(target))
            opt_state->start_revision.kind = svn_opt_revision_head;
          else
            opt_state->start_revision.kind = svn_opt_revision_base;
        }
      else
        opt_state->start_revision = peg_revision;

      if (opt_state->end_revision.kind == svn_opt_revision_unspecified)
        {
          opt_state->end_revision.kind = svn_opt_revision_number;
          opt_state->end_revision.value.number = 0;
        }
    }

  if (svn_path_is_url(target))
    {
      for (i = 1; i < targets->nelts; i++)
        {
          target = APR_ARRAY_IDX(targets, i, const char *);

          if (svn_path_is_url(target))
            return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                                    _("Only relative paths can be specified "
                                      "after a URL"));
        }
    }

  lb.cancel_func = ctx->cancel_func;
  lb.cancel_baton = ctx->cancel_baton;
  lb.omit_log_message = opt_state->quiet;
  lb.merge_stack = apr_array_make(pool, 0, sizeof(svn_revnum_t));
  lb.pool = pool;

  if (! opt_state->quiet)
    svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2, FALSE,
                         FALSE, FALSE, pool);

  if (opt_state->xml)
    {
      /* If output is not incremental, output the XML header and wrap
         everything in a top-level element. This makes the output in
         its entirety a well-formed XML document. */
      if (! opt_state->incremental)
        SVN_ERR(svn_cl__xml_print_header("log", pool));

      if (opt_state->all_revprops)
        revprops = NULL;
      else if (opt_state->revprop_table != NULL)
        {
          apr_hash_index_t *hi;
          revprops = apr_array_make(pool,
                                    apr_hash_count(opt_state->revprop_table),
                                    sizeof(char *));
          for (hi = apr_hash_first(pool, opt_state->revprop_table);
               hi != NULL;
               hi = apr_hash_next(hi))
            {
              char *property;
              svn_string_t *value;
              apr_hash_this(hi, (void *)&property, NULL, (void *)&value);
              if (value && value->data[0] != '\0')
                return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                         _("cannot assign with 'with-revprop'"
                                           " option (drop the '=')"));
              APR_ARRAY_PUSH(revprops, char *) = property;
            }
        }
      else
        {
          revprops = apr_array_make(pool, 3, sizeof(char *));
          APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_AUTHOR;
          APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_DATE;
          if (!opt_state->quiet)
            APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_LOG;
        }
      SVN_ERR(svn_client_log4(targets,
                              &peg_revision,
                              &(opt_state->start_revision),
                              &(opt_state->end_revision),
                              opt_state->limit,
                              opt_state->verbose,
                              opt_state->stop_on_copy,
                              opt_state->use_merge_history,
                              revprops,
                              log_entry_receiver_xml,
                              &lb,
                              ctx,
                              pool));

      if (! opt_state->incremental)
        SVN_ERR(svn_cl__xml_print_footer("log", pool));
    }
  else  /* default output format */
    {
      revprops = apr_array_make(pool, 3, sizeof(char *));
      APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_AUTHOR;
      APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_DATE;
      if (!opt_state->quiet)
        APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_LOG;
      SVN_ERR(svn_client_log4(targets,
                              &peg_revision,
                              &(opt_state->start_revision),
                              &(opt_state->end_revision),
                              opt_state->limit,
                              opt_state->verbose,
                              opt_state->stop_on_copy,
                              opt_state->use_merge_history,
                              revprops,
                              log_entry_receiver,
                              &lb,
                              ctx,
                              pool));

      if (! opt_state->incremental)
        SVN_ERR(svn_cmdline_printf(pool, SEP_STRING));
    }

  return SVN_NO_ERROR;
}
// PYSVN_HAS_CLIENT_LOG4 version
Py::Object pysvn_client::cmd_log( const Py::Tuple &a_args, const Py::Dict &a_kws )
{
    static argument_description args_desc[] =
    {
    { true,  name_url_or_path },
    { false, name_revision_start },
    { false, name_revision_end },
    { false, name_discover_changed_paths },
    { false, name_strict_node_history },
    { false, name_limit },
    { false, name_peg_revision },
    { false, name_include_merged_revisions },
    { false, name_revprops },
    { false, NULL }
    };
    FunctionArguments args( "log", args_desc, a_args, a_kws );
    args.check();

    SvnPool pool( m_context );

    svn_opt_revision_t revision_start = args.getRevision( name_revision_start, svn_opt_revision_head );
    svn_opt_revision_t revision_end = args.getRevision( name_revision_end, svn_opt_revision_number );
    bool discover_changed_paths = args.getBoolean( name_discover_changed_paths, false );
    bool strict_node_history = args.getBoolean( name_strict_node_history, true );
    int limit = args.getInteger( name_limit, 0 );
    svn_opt_revision_t peg_revision = args.getRevision( name_peg_revision, svn_opt_revision_unspecified );

    svn_boolean_t include_merged_revisions = args.getBoolean( name_include_merged_revisions, false );
    apr_array_header_t *revprops = NULL;
    if( args.hasArg( name_revprops ) )
    {
        Py::Object py_revprop = args.getArg( name_revprops );
        if( !py_revprop.isNone() )
        {
            revprops = arrayOfStringsFromListOfStrings( py_revprop, pool );
        }
    }

    Py::Object url_or_path_obj = args.getArg( name_url_or_path );
    Py::List url_or_path_list;
    if( url_or_path_obj.isList() )
    {
        url_or_path_list = url_or_path_obj;
    }
    else
    {
        Py::List py_list;
        py_list.append( url_or_path_obj );
        url_or_path_list = py_list;
    }

    for( size_t i=0; i<url_or_path_list.size(); i++ )
    {
        Py::Bytes py_path( asUtf8Bytes( url_or_path_list[ i ] ) );
        std::string path( py_path.as_std_string() );
        bool is_url = is_svn_url( path );

        revisionKindCompatibleCheck( is_url, peg_revision, name_peg_revision, name_url_or_path );
        revisionKindCompatibleCheck( is_url, revision_start, name_revision_start, name_url_or_path );
        revisionKindCompatibleCheck( is_url, revision_end, name_revision_end, name_url_or_path );
    }

    apr_array_header_t *targets = targetsFromStringOrList( url_or_path_list, pool );

    Py::List log_list;

    try
    {
        checkThreadPermission();

        PythonAllowThreads permission( m_context );

        Log4Baton baton( &permission, pool, log_list );
        baton.m_wrapper_log = &m_wrapper_log;
        baton.m_wrapper_log_changed_path = &m_wrapper_log_changed_path;

#if defined( PYSVN_HAS_CLIENT_LOG5 )
        apr_array_header_t *revision_ranges = apr_array_make( pool, 0, sizeof(svn_opt_revision_range_t *) );
        svn_opt_revision_range_t *range = reinterpret_cast<svn_opt_revision_range_t *>( apr_palloc( pool, sizeof(*range) ) );

        range->start = revision_start;
        range->end = revision_end;

        APR_ARRAY_PUSH( revision_ranges, svn_opt_revision_range_t * ) = range;

        svn_error_t *error = svn_client_log5
            (
            targets,
            &peg_revision,
            revision_ranges,
            limit,
            discover_changed_paths,
            strict_node_history,
            include_merged_revisions,
            revprops,
            log4Receiver,
            reinterpret_cast<void *>( &baton ),
            m_context,
            pool
            );
#else
        svn_error_t *error = svn_client_log4
            (
            targets,
            &peg_revision,
            &revision_start,
            &revision_end,
            limit,
            discover_changed_paths,
            strict_node_history,
            include_merged_revisions,
            revprops,
            log4Receiver,
            reinterpret_cast<void *>( &baton ),
            m_context,
            pool
            );
#endif
        permission.allowThisThread();
        if( error != NULL )
            throw SvnException( error );
    }
    catch( SvnException &e )
    {
        // use callback error over ClientException
        m_context.checkForError( m_module.client_error );

        throw_client_error( e );
    }

    return log_list;
}
// PYSVN_HAS_CLIENT_LOG, PYSVN_HAS_CLIENT_LOG2, PYSVN_HAS_CLIENT_LOG3 version
Py::Object pysvn_client::cmd_log( const Py::Tuple &a_args, const Py::Dict &a_kws )
{
    static argument_description args_desc[] =
    {
    { true,  name_url_or_path },
    { false, name_revision_start },
    { false, name_revision_end },
    { false, name_discover_changed_paths },
    { false, name_strict_node_history },
#if defined( PYSVN_HAS_CLIENT_LOG2 ) || defined( PYSVN_HAS_CLIENT_LOG3 )
    { false, name_limit },
#endif
#if defined( PYSVN_HAS_CLIENT_LOG3 )
    { false, name_peg_revision },
#endif
#if defined( PYSVN_HAS_CLIENT_LOG4 )
    { false, name_include_merged_revisions },
    { false, name_revprops },
#endif
    { false, NULL }
    };
    FunctionArguments args( "log", args_desc, a_args, a_kws );
    args.check();

    svn_opt_revision_t revision_start = args.getRevision( name_revision_start, svn_opt_revision_head );
    svn_opt_revision_t revision_end = args.getRevision( name_revision_end, svn_opt_revision_number );
    bool discover_changed_paths = args.getBoolean( name_discover_changed_paths, false );
    bool strict_node_history = args.getBoolean( name_strict_node_history, true );
    int limit = args.getInteger( name_limit, 0 );
#if defined( PYSVN_HAS_CLIENT_LOG3 )
    svn_opt_revision_t peg_revision = args.getRevision( name_peg_revision, svn_opt_revision_unspecified );
#endif
#if defined( PYSVN_HAS_CLIENT_LOG4 )
    svn_boolean_t include_merged_revisions = args.getBoolean( name_include_merged_revisions, false );
    apr_array_header_t *revprops = NULL;
    Py::Object py_revprop = args.getArg( name_revprops );
    if( py_revprop is not None )
    {
        revprops = arrayOfStringsFromListOfStrings( py_revprop. pool );
    }
#endif

    Py::Object url_or_path_obj = args.getArg( name_url_or_path );
    Py::List url_or_path_list;
    if( url_or_path_obj.isList() )
    {
        url_or_path_list = url_or_path_obj;
    }
    else
    {
        Py::List py_list;
        py_list.append( url_or_path_obj );
        url_or_path_list = py_list;
    }

    for( size_t i=0; i<url_or_path_list.size(); i++ )
    {
        Py::Bytes py_path( asUtf8Bytes( url_or_path_list[ i ] ) );
        std::string path( py_path.as_std_string() );
        bool is_url = is_svn_url( path );

        // std::cout << "peg_revision "    << peg_revision.kind    << " " << peg_revision.value.number     << std::endl;
        // std::cout << "revision_start "  << revision_start.kind  << " " << revision_start.value.number   << std::endl;
        // std::cout << "revision_end "    << revision_end.kind    << " " << revision_end.value.number     << std::endl;

#if defined( PYSVN_HAS_CLIENT_LOG3 )
        revisionKindCompatibleCheck( is_url, peg_revision, name_peg_revision, name_url_or_path );
#endif
        revisionKindCompatibleCheck( is_url, revision_start, name_revision_start, name_url_or_path );
        revisionKindCompatibleCheck( is_url, revision_end, name_revision_end, name_url_or_path );
    }

    SvnPool pool( m_context );

    apr_array_header_t *targets = targetsFromStringOrList( url_or_path_list, pool );

#if defined( PYSVN_HAS_CLIENT_LOG4 )
    Log4Baton baton( permission, pool );
#else
    std::list<LogEntryInfo> all_entries;
#endif

    try
    {
        checkThreadPermission();

        PythonAllowThreads permission( m_context );

#if defined( PYSVN_HAS_CLIENT_LOG4 )
        svn_error_t *error = svn_client_log4
            (
            targets,
            &peg_revision,
            &revision_start,
            &revision_end,
            limit,
            discover_changed_paths,
            strict_node_history,
            include_merged_revisions,
            revprops,
            logReceiver,
            &all_entries,
            m_context,
            pool
            );
#elif defined( PYSVN_HAS_CLIENT_LOG3 )
        svn_error_t *error = svn_client_log3
            (
            targets,
            &peg_revision,
            &revision_start,
            &revision_end,
            limit,
            discover_changed_paths,
            strict_node_history,
            logReceiver,
            &all_entries,
            m_context,
            pool
            );
#elif defined( PYSVN_HAS_CLIENT_LOG2 )
        svn_error_t *error = svn_client_log2
            (
            targets,
            &revision_start,
            &revision_end,
            limit,
            discover_changed_paths,
            strict_node_history,
            logReceiver,
            &all_entries,
            m_context,
            pool
            );
#else
        svn_error_t *error = svn_client_log
            (
            targets,
            &revision_start,
            &revision_end,
            discover_changed_paths,
            strict_node_history,
            logReceiver,
            &all_entries,
            m_context,
            pool
            );
#endif
        permission.allowThisThread();
        if( error != NULL )
            throw SvnException( error );
    }
    catch( SvnException &e )
    {
        // use callback error over ClientException
        m_context.checkForError( m_module.client_error );

        throw_client_error( e );
    }

    apr_time_t now = apr_time_now();

    // convert the entries into python objects
    Py::List entries_list;
    std::list<LogEntryInfo>::const_iterator entry_it = all_entries.begin();
    while( entry_it != all_entries.end() )
    {
        const LogEntryInfo &entry = *entry_it;
        ++entry_it;

        Py::Dict entry_dict;
        entry_dict[name_author] = Py::String( entry.m_author, name_utf8 );
        entry_dict[name_date] = toObject( convertStringToTime( entry.m_date, now, pool ) );
        entry_dict[name_message] = Py::String( entry.m_message, name_utf8 );
        entry_dict[name_revision] = Py::asObject( new pysvn_revision( svn_opt_revision_number, 0, entry.m_revision ) );

        Py::List changed_paths_list;
        std::list<LogChangePathInfo>::const_iterator changed_paths_it = entry.m_changed_paths.begin();
        while( changed_paths_it != entry.m_changed_paths.end() )
        {
            const LogChangePathInfo &change_entry = *changed_paths_it;
            ++changed_paths_it;

            Py::Dict changed_entry_dict;
            changed_entry_dict[name_path] = Py::String( change_entry.m_path, name_utf8 );
            changed_entry_dict[name_action] = Py::String( &change_entry.m_action, 1 );
            changed_entry_dict[name_copyfrom_path] = utf8_string_or_none( change_entry.m_copy_from_path );

            if( SVN_IS_VALID_REVNUM( change_entry.m_copy_from_revision ) )
                changed_entry_dict[name_copyfrom_revision] = Py::asObject( new pysvn_revision( svn_opt_revision_number, 0, change_entry.m_copy_from_revision ) );
            else
                changed_entry_dict[name_copyfrom_revision] = Py::None();

            changed_paths_list.append( m_wrapper_log_changed_path.wrapDict( changed_entry_dict ) );
        }

        entry_dict[name_changed_paths] = changed_paths_list;

        entries_list.append( m_wrapper_log.wrapDict( entry_dict ) );
    }

    return entries_list;
}
Exemple #4
0
/* fonction simulant la commande svn log */
apr_array_header_t *svn_support_log_call(char *rep_path, 
                                         int start, 
                                         int end, 
                                         int limit, 
                                         apr_pool_t *subpool)
{  
  svn_error_t *err;
  svn_opt_revision_t revision_start;
  svn_opt_revision_t revision_end;

  
  // -- Initialisation de la cible --
  apr_array_header_t *targets = apr_array_make (subpool, 1, sizeof (char *));
  *(char **)apr_array_push(targets) = rep_path;
  
  // -- Initialisation de l'intervalle de revisions --
  if (end == -1) { 
    if (start == -1) {
      revision_start.kind = svn_opt_revision_head;
      revision_end.kind = svn_opt_revision_number;
      revision_end.value.number = 1;
    }
    else {
      revision_start.kind = svn_opt_revision_number;
      revision_start.value.number = start;
      revision_end.kind = svn_opt_revision_head;
    }
  }
  else {
    if (start == -1) {
      revision_start.kind = svn_opt_revision_number;
      revision_start.value.number = end;
      revision_end.kind = svn_opt_revision_number;
      revision_end.value.number = 1;
    }
    else {
      revision_start.kind = svn_opt_revision_number;
      revision_start.value.number = start;
      revision_end.kind = svn_opt_revision_number;
      revision_end.value.number = end;
    }
  }
    
  // -- Choix des propriétés a récupérer --
  apr_array_header_t *revprops = apr_array_make (subpool, 3, sizeof (char *));
  *(char **)apr_array_push(revprops) = SVN_PROP_REVISION_AUTHOR;
  *(char **)apr_array_push(revprops) = SVN_PROP_REVISION_DATE;
  *(char **)apr_array_push(revprops) = SVN_PROP_REVISION_LOG;

  // -- Initialisation du tableau et du buffer de résultats -- 
  apr_array_header_t *list_result = apr_array_make(subpool, 1, sizeof (const char *));
  svn_stringbuf_t *res = svn_stringbuf_create("",subpool);	
  err = svn_client_log4(targets,
			&revision_start,
			&revision_start,
			&revision_end,
			limit,
			FALSE,
			TRUE,
			FALSE,
			revprops,
			log_callback,
			res,
			ctx,
			subpool);
  
  if (err) {
    svn_handle_error2(err, stderr, FALSE, "svn_support_log: ");
    svn_pool_destroy(subpool);
    return NULL;
  }
  svn_cstring_split_append(list_result,res->data,"\n",FALSE,subpool);
  svn_pool_destroy(subpool);
  return list_result;
}