export.c

来自「linux subdivision ying gai ke yi le ba」· C语言 代码 · 共 869 行 · 第 1/2 页

C
869
字号
           apr_pool_t *pool,
           void **root_baton)
{
  struct edit_baton *eb = edit_baton;  
  struct dir_baton *db = apr_pcalloc (pool, sizeof (*db));

  SVN_ERR (open_root_internal (eb->root_path, eb->force,
                               eb->notify_func, eb->notify_baton, pool));

  /* Build our dir baton. */
  db->path = eb->root_path;
  db->edit_baton = eb;
  *root_baton = db;
  
  return SVN_NO_ERROR;
}


/* Ensure the directory exists, and send feedback. */
static svn_error_t *
add_directory (const char *path,
               void *parent_baton,
               const char *copyfrom_path,
               svn_revnum_t copyfrom_revision,
               apr_pool_t *pool,
               void **baton)
{
  struct dir_baton *pb = parent_baton;
  struct dir_baton *db = apr_pcalloc (pool, sizeof (*db));
  struct edit_baton *eb = pb->edit_baton;
  const char *full_path = svn_path_join (eb->root_path, path, pool);
  svn_node_kind_t kind;

  SVN_ERR (svn_io_check_path (full_path, &kind, pool));
  if (kind == svn_node_none)
    SVN_ERR (svn_io_dir_make (full_path, APR_OS_DEFAULT, pool));
  else if (kind == svn_node_file)
    return svn_error_createf (SVN_ERR_WC_NOT_DIRECTORY, NULL,
                              _("'%s' exists and is not a directory"),
                              full_path);
  else if (! (kind == svn_node_dir && eb->force))
    return svn_error_createf (SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
                              _("'%s' already exists"), full_path);

  if (eb->notify_func)
    (*eb->notify_func) (eb->notify_baton,
                        full_path,
                        svn_wc_notify_update_add,
                        svn_node_dir,
                        NULL,
                        svn_wc_notify_state_unknown,
                        svn_wc_notify_state_unknown,
                        SVN_INVALID_REVNUM);

  
  /* Build our dir baton. */
  db->path = full_path;
  db->edit_baton = eb;
  *baton = db;

  return SVN_NO_ERROR;
}


/* Build a file baton. */
static svn_error_t *
add_file (const char *path,
          void *parent_baton,
          const char *copyfrom_path,
          svn_revnum_t copyfrom_revision,
          apr_pool_t *pool,
          void **baton)
{
  struct dir_baton *pb = parent_baton;
  struct edit_baton *eb = pb->edit_baton;
  struct file_baton *fb = apr_pcalloc (pool, sizeof(*fb));
  const char *full_path = svn_path_join (eb->root_path, path, pool);
  const char *full_url = svn_path_join (eb->root_url, path, pool);

  fb->edit_baton = eb;
  fb->path = full_path;
  fb->url = full_url;
  fb->pool = pool;

  *baton = fb;
  return SVN_NO_ERROR;
}


static svn_error_t *
window_handler (svn_txdelta_window_t *window, void *baton)
{
  struct handler_baton *hb = baton;
  svn_error_t *err;

  err = hb->apply_handler (window, hb->apply_baton);
  if (err)
    {
      /* We failed to apply the patch; clean up the temporary file.  */
      apr_file_remove (hb->tmppath, hb->pool);
    }

  return err;
}



/* Write incoming data into the tmpfile stream */
static svn_error_t *
apply_textdelta (void *file_baton,
                 const char *base_checksum,
                 apr_pool_t *pool,
                 svn_txdelta_window_handler_t *handler,
                 void **handler_baton)
{
  struct file_baton *fb = file_baton;
  struct handler_baton *hb = apr_palloc (pool, sizeof (*hb));

  SVN_ERR (svn_io_open_unique_file (&fb->tmp_file, &(fb->tmppath),
                                    fb->path, ".tmp", FALSE, fb->pool));

  hb->pool = pool;
  hb->tmppath = fb->tmppath;

  svn_txdelta_apply (svn_stream_empty (pool),
                     svn_stream_from_aprfile (fb->tmp_file, pool),
                     fb->text_digest, NULL, pool,
                     &hb->apply_handler, &hb->apply_baton);

  *handler_baton = hb;
  *handler = window_handler;
  return SVN_NO_ERROR;
}


static svn_error_t *
change_file_prop (void *file_baton,
                  const char *name,
                  const svn_string_t *value,
                  apr_pool_t *pool)
{
  struct file_baton *fb = file_baton;

  if (! value)
    return SVN_NO_ERROR;

  /* Store only the magic three properties. */
  if (strcmp (name, SVN_PROP_EOL_STYLE) == 0)
    fb->eol_style_val = svn_string_dup (value, fb->pool);

  else if (strcmp (name, SVN_PROP_KEYWORDS) == 0)
    fb->keywords_val = svn_string_dup (value, fb->pool);

  else if (strcmp (name, SVN_PROP_EXECUTABLE) == 0)
    fb->executable_val = svn_string_dup (value, fb->pool);

  /* Try to fill out the baton's keywords-structure too. */
  else if (strcmp (name, SVN_PROP_ENTRY_COMMITTED_REV) == 0)
    fb->revision = apr_pstrdup (fb->pool, value->data);

  else if (strcmp (name, SVN_PROP_ENTRY_COMMITTED_DATE) == 0)
      SVN_ERR (svn_time_from_cstring (&fb->date, value->data, fb->pool));

  else if (strcmp (name, SVN_PROP_ENTRY_LAST_AUTHOR) == 0)
    fb->author = apr_pstrdup (fb->pool, value->data);

  else if (strcmp (name, SVN_PROP_SPECIAL) == 0)
    fb->special = TRUE;

  return SVN_NO_ERROR;
}


static svn_error_t *
change_dir_prop (void *dir_baton,
                 const char *name,
                 const svn_string_t *value,
                 apr_pool_t *pool)
{
  struct dir_baton *db = dir_baton;
  struct edit_baton *eb = db->edit_baton;

  if (value && (strcmp (name, SVN_PROP_EXTERNALS) == 0))
    add_externals (eb->externals, db->path, value);

  return SVN_NO_ERROR;
}


/* Move the tmpfile to file, and send feedback. */
static svn_error_t *
close_file (void *file_baton,
            const char *text_checksum,
            apr_pool_t *pool)
{
  struct file_baton *fb = file_baton;
  struct edit_baton *eb = fb->edit_baton;

  /* Was a txdelta even sent? */
  if (! fb->tmppath)
    return SVN_NO_ERROR;

  SVN_ERR (svn_io_file_close (fb->tmp_file, fb->pool));

  if (text_checksum)
    {
      const char *actual_checksum
        = svn_md5_digest_to_cstring (fb->text_digest, pool);

      if (actual_checksum && (strcmp (text_checksum, actual_checksum) != 0))
        {
          return svn_error_createf
            (SVN_ERR_CHECKSUM_MISMATCH, NULL,
             _("Checksum mismatch for '%s'; expected: '%s', actual: '%s'"),
             fb->path, text_checksum, actual_checksum);
        }
    }

  if ((! fb->eol_style_val) && (! fb->keywords_val) && (! fb->special))
    {
      SVN_ERR (svn_io_file_rename (fb->tmppath, fb->path, pool));
    }
  else
    {
      svn_subst_eol_style_t style;
      const char *eol;
      svn_subst_keywords_t final_kw = {0};

      if (fb->eol_style_val)
        SVN_ERR (get_eol_style (&style, &eol, fb->eol_style_val->data, 
                                eb->native_eol));

      if (fb->keywords_val)
        SVN_ERR (svn_subst_build_keywords (&final_kw, fb->keywords_val->data, 
                                           fb->revision, fb->url, fb->date, 
                                           fb->author, pool));

      SVN_ERR (svn_subst_copy_and_translate2
               (fb->tmppath, fb->path,
                fb->eol_style_val ? eol : NULL,
                fb->eol_style_val ? TRUE : FALSE, /* repair */
                fb->keywords_val ? &final_kw : NULL,
                TRUE, /* expand */
                fb->special,
                pool));

      SVN_ERR (svn_io_remove_file (fb->tmppath, pool));
    }
      
  if (fb->executable_val)
    SVN_ERR (svn_io_set_file_executable (fb->path, TRUE, FALSE, pool));

  if (fb->date && (! fb->special))
    SVN_ERR (svn_io_set_file_affected_time (fb->date, fb->path, pool));

  if (fb->edit_baton->notify_func)
    (*fb->edit_baton->notify_func) (fb->edit_baton->notify_baton,
                                    fb->path,
                                    svn_wc_notify_update_add,
                                    svn_node_file,
                                    NULL,
                                    svn_wc_notify_state_unknown,
                                    svn_wc_notify_state_unknown,
                                    SVN_INVALID_REVNUM);

  return SVN_NO_ERROR;
}



/*** Public Interfaces ***/

svn_error_t *
svn_client_export2 (svn_revnum_t *result_rev,
                    const char *from,
                    const char *to,
                    svn_opt_revision_t *revision,
                    svn_boolean_t force, 
                    const char *native_eol,
                    svn_client_ctx_t *ctx,
                    apr_pool_t *pool)
{
  svn_revnum_t edit_revision = SVN_INVALID_REVNUM;
  svn_boolean_t use_ra = FALSE;
  const char *URL;

  if (! svn_path_is_url (from) &&
      (revision->kind != svn_opt_revision_base) &&
      (revision->kind != svn_opt_revision_committed) &&
      (revision->kind != svn_opt_revision_working))
    {
      if (revision->kind == svn_opt_revision_unspecified)
        {
          /* Default to WORKING in the case that we have
             been given a working copy path */
          revision->kind = svn_opt_revision_working;
        }
      else
        {
          use_ra = TRUE;
          SVN_ERR (svn_client_url_from_path (&URL, from, pool));
          if (! URL)
            return svn_error_createf (SVN_ERR_ENTRY_MISSING_URL, NULL,
                                      _("'%s' has no URL"), from);
        }
    }
  else
    {
      URL = svn_path_canonicalize (from, pool);
    }

  if (svn_path_is_url (from) || use_ra)
    {
      svn_revnum_t revnum;
      void *ra_baton, *session;
      svn_ra_plugin_t *ra_lib;
      void *edit_baton;
      svn_node_kind_t kind;
      const svn_delta_editor_t *export_editor;
      const svn_ra_reporter_t *reporter;
      void *report_baton;
      struct edit_baton *eb = apr_pcalloc (pool, sizeof (*eb));
      svn_delta_editor_t *editor = svn_delta_default_editor (pool);
      svn_boolean_t use_sleep = FALSE;

      eb->root_path = to;
      eb->root_url = URL;
      eb->force = force;
      eb->target_revision = &edit_revision;
      eb->notify_func = ctx->notify_func;
      eb->notify_baton = ctx->notify_baton;
      eb->externals = apr_hash_make (pool);
      eb->native_eol = native_eol; 

      editor->set_target_revision = set_target_revision;
      editor->open_root = open_root;
      editor->add_directory = add_directory;
      editor->add_file = add_file;
      editor->apply_textdelta = apply_textdelta;
      editor->close_file = close_file;
      editor->change_file_prop = change_file_prop;
      editor->change_dir_prop = change_dir_prop;
      
      SVN_ERR (svn_delta_get_cancellation_editor (ctx->cancel_func,
                                                  ctx->cancel_baton,
                                                  editor,
                                                  eb,
                                                  &export_editor,
                                                  &edit_baton,
                                                  pool));
  
      SVN_ERR (svn_ra_init_ra_libs (&ra_baton, pool));
      SVN_ERR (svn_ra_get_ra_library (&ra_lib, ra_baton, URL, pool));

      SVN_ERR (svn_client__open_ra_session (&session, ra_lib, URL, NULL,
                                            NULL, NULL, FALSE, TRUE,
                                            ctx, pool));

      /* Unfortunately, it's not kosher to pass an invalid revnum into
         set_path(), so we actually need to convert it to HEAD. */
      if (revision->kind == svn_opt_revision_unspecified)
        revision->kind = svn_opt_revision_head;
      SVN_ERR (svn_client__get_revision_number
               (&revnum, ra_lib, session, revision, from, pool));

      /* Manufacture a basic 'report' to the update reporter. */
      SVN_ERR (ra_lib->do_update (session,
                                  &reporter, &report_baton,
                                  revnum,
                                  "", /* no sub-target */
                                  TRUE, /* recurse */
                                  export_editor, edit_baton, pool));

      SVN_ERR (reporter->set_path (report_baton, "", revnum,
                                   TRUE, /* "help, my dir is empty!" */
                                   pool));

      SVN_ERR (reporter->finish_report (report_baton, pool));               

      /* Special case: Due to our sly export/checkout method of
       * updating an empty directory, no target will have been created
       * if the exported item is itself an empty directory
       * (export_editor->open_root never gets called, because there
       * are no "changes" to make to the empty dir we reported to the
       * repository).
       *
       * So we just create the empty dir manually; but we do it via
       * open_root_internal(), in order to get proper notification.
       */
      SVN_ERR (svn_io_check_path (to, &kind, pool));
      if (kind == svn_node_none)
        SVN_ERR (open_root_internal
                 (to, force, ctx->notify_func, ctx->notify_baton, pool));

      SVN_ERR (svn_client__fetch_externals (eb->externals, TRUE, 
                                            &use_sleep, ctx, pool));
    }
  else
    {
      /* just copy the contents of the working copy into the target path. */
      SVN_ERR (copy_versioned_files (from, to, revision, force, native_eol,
                                     ctx, pool));
    }

  if (ctx->notify_func)
    (*ctx->notify_func) (ctx->notify_baton,
                         to,
                         svn_wc_notify_update_completed,
                         svn_node_unknown,
                         NULL,
                         svn_wc_notify_state_unknown,
                         svn_wc_notify_state_unknown,
                         edit_revision);

  if (result_rev)
    *result_rev = edit_revision;

  return SVN_NO_ERROR;
}


svn_error_t *
svn_client_export (svn_revnum_t *result_rev,
                   const char *from,
                   const char *to,
                   svn_opt_revision_t *revision,
                   svn_boolean_t force, 
                   svn_client_ctx_t *ctx,
                   apr_pool_t *pool)
{
  return svn_client_export2 (result_rev, from, to, revision, force, NULL, ctx,
                             pool);
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?