On 1 Oct 2003, C. Michael Pilato wrote:
> Martin Furter <mf@rola.ch> writes:
>
> > Yes, that works very well, only one issue remaining: i don't have the
> > mimetype anymore which is used in the notify_func (f.ex. at the end of
> > svn_wc_add):
> >
> > /* Report the addition to the caller. */
> > if (notify_func != NULL)
> > (*notify_func) (notify_baton, path, svn_wc_notify_add,
> > kind,
> > NULL, <--- this was mimetype
> > svn_wc_notify_state_unknown,
> > svn_wc_notify_state_unknown,
> > SVN_INVALID_REVNUM);
> >
> > In import_file i can get it back because i have the hash containing the
> > properties, but in svn_wc_add i can't.
> > I could make a notify_func which stores the data in a baton and call the
> > real notify_func after getting the auto-props.
> >
> > Or is it ok to use always NULL for mimetype ?
>
> If I'm thinking of the right spot, using NULL is the difference
> between seeing:
>
> A /some/path
>
> and:
>
> A (bin) /some/path
>
> In other words, we do use the mimetype to point out places where the
> code has made an automatic decision about binariness (which effects
> lots of things -- the ability to do contextual merging, ability to set
> EOL properties, etc.)
>
> Is this is a necessary feature? I have no strong opinions.
While implementing the mimetype again i saw that svn_wc_add uses either
constants or parameter known to libsvn_client in the call to the notify
function.
So i can call notify_func from the new add_file() function and give NULL
as notify_func to svn_wc_add().
I hope this patch is now acceptable.
Martin
----- log message -----
Automatic properties for 'svn add' and 'svn import' added (issue #1502).
* build.conf
([fs-test-scripts]): Added autoprop_tests.py
* subversion/include/svn_config.h
(SVN_CONFIG_OPTION_ENABLE_AUTO_PROPS, SVN_CONFIG_SECTION_AUTO_PROPS):
New defines.
* subversion/libsvn_wc/adm_ops.c
(svn_wc_add): Removed mimetype/executable detection.
* subversion/libsvn_subr/config_file.c
(svn_config_ensure): Config entries added.
* subversion/libsvn_client/client.h
(svn_client__get_auto_props): Prototype added.
* subversion/libsvn_client/commit.c
(import_file): Call svn_client__get_auto_props and set the properties,
detection of mimetype and executable removed.
* subversion/libsvn_client/add.c
(auto_props_baton_t): New struct, local usage only.
(auto_props_enumerator): New function, used by
svn_client__get_auto_props.
(svn_client__get_auto_props): New function, searches automatic
properties in the config, detects mimetype/executable if needed.
(add_file): New function, adds a file with automatic properties and
calls notify_func.
(add_dir_recursive, add): When adding a file call add_file() instead of
svn_wc_add().
* subversion/clients/cmdline/cl.h
(svn_cl__longopt_t): Added svn_cl__autoprops_opt and
svn_cl__no_autoprops_opt.
(svn_cl__opt_state_t): Added autoprops and no_autoprops.
* subversion/clients/cmdline/main.c
(svn_cl__options, svn_cl__cmd_table): Added svn_cl__autoprops_opt
and svn_cl__no_autoprops_opt.
(main): Process svn_cl__autoprops_opt and svn_cl__no_autoprops_opt and
overwrite SVN_CONFIG_OPTION_ENABLE_AUTO_PROPS.
* subversion/tests/clients/cmdline/autoprop_tests.py
New file containing tests for auto-props.
* subversion/tests/clients/cmdline/svntest/main.py
Added default_config_dir, set_config_dir() and reset_config_dir().
----- end of log message -----
----- auto-props patch -----
Index: build.conf
===================================================================
--- build.conf (revision 7267)
+++ build.conf (working copy)
@@ -55,6 +55,7 @@
subversion/tests/clients/cmdline/merge_tests.py
subversion/tests/clients/cmdline/stat_tests.py
subversion/tests/clients/cmdline/trans_tests.py
+ subversion/tests/clients/cmdline/autoprop_tests.py
subversion/tests/clients/cmdline/svnadmin_tests.py
subversion/tests/clients/cmdline/svnlook_tests.py
subversion/tests/clients/cmdline/svnversion_tests.py
Index: subversion/include/svn_config.h
===================================================================
--- subversion/include/svn_config.h (revision 7267)
+++ subversion/include/svn_config.h (working copy)
@@ -81,7 +81,9 @@
#define SVN_CONFIG_OPTION_LOG_ENCODING "log-encoding"
#define SVN_CONFIG_OPTION_USE_COMMIT_TIMES "use-commit-times"
#define SVN_CONFIG_OPTION_TEMPLATE_ROOT "template-root"
+#define SVN_CONFIG_OPTION_ENABLE_AUTO_PROPS "enable-auto-props"
#define SVN_CONFIG_SECTION_TUNNELS "tunnels"
+#define SVN_CONFIG_SECTION_AUTO_PROPS "auto-props"
/*** Configuration Default Values ***/
Index: subversion/libsvn_wc/adm_ops.c
===================================================================
--- subversion/libsvn_wc/adm_ops.c (revision 7267)
+++ subversion/libsvn_wc/adm_ops.c (working copy)
@@ -888,8 +888,6 @@
svn_boolean_t is_replace = FALSE;
svn_node_kind_t kind;
apr_uint32_t modify_flags = 0;
- const char *mimetype = NULL;
- svn_boolean_t executable = FALSE;
svn_wc_adm_access_t *adm_access;
/* Make sure something's there. */
@@ -996,40 +994,10 @@
SVN_ERR (remove_file_if_present (prop_path, pool));
}
- if (kind == svn_node_file)
+ if (kind == svn_node_dir) /* scheduling a directory for addition */
{
- /* If this is a new file being added instead of a file copy,
- then try to detect the mime-type of this file and set
- svn:executable if the file is executable. Otherwise, use the
- values in the original file. */
if (! copyfrom_url)
{
- SVN_ERR (svn_io_detect_mimetype (&mimetype, path, pool));
- if (mimetype)
- {
- svn_string_t mt_str;
- mt_str.data = mimetype;
- mt_str.len = strlen(mimetype);
- SVN_ERR (svn_wc_prop_set (SVN_PROP_MIME_TYPE, &mt_str, path,
- parent_access, pool));
- }
-
- /* Set svn:executable if the new addition is executable. */
- SVN_ERR (svn_io_is_file_executable (&executable, path, pool));
- if (executable)
- {
- svn_string_t emptystr;
- emptystr.data = "";
- emptystr.len = 0;
- SVN_ERR (svn_wc_prop_set (SVN_PROP_EXECUTABLE, &emptystr, path,
- parent_access, pool));
- }
- }
- }
- else /* scheduling a directory for addition */
- {
- if (! copyfrom_url)
- {
const svn_wc_entry_t *p_entry; /* ### why not use parent_entry? */
const char *new_url;
@@ -1112,7 +1080,7 @@
if (notify_func != NULL)
(*notify_func) (notify_baton, path, svn_wc_notify_add,
kind,
- mimetype,
+ NULL,
svn_wc_notify_state_unknown,
svn_wc_notify_state_unknown,
SVN_INVALID_REVNUM);
Index: subversion/libsvn_subr/config_file.c
===================================================================
--- subversion/libsvn_subr/config_file.c (revision 7267)
+++ subversion/libsvn_subr/config_file.c (working copy)
@@ -978,7 +978,30 @@
"### Set use-commit-times to make checkout/update/switch/revert\n"
"### put last-committed timestamps on every file touched.\n"
"# use-commit-times = yes\n"
+ "### Enable automatic properties for 'svn add' (true | false).\n"
+ "### Automatic properties are defined in the section 'auto-props'.\n"
+ "# enable-auto-props-add = true\n"
+ "### Enable automatic properties for 'svn import' (true | false).\n"
+ "# enable-auto-props-imp = true\n"
"\n"
+ "### Section for configuring automatic properties.\n"
+ "### The format of the entries is:\n"
+ "### file-name-pattern = propname[=value][;propname[=value]...]\n"
+ "### The file-name-pattern can contain * as wildcard. All entries\n"
+ "### which match will be applied to the file.\n"
+ "# [auto-props]\n"
+ "# *.c = svn:eol-style=native\n"
+ "# *.cpp = svn:eol-style=native\n"
+ "# *.h = svn:eol-style=native\n"
+ "# *.dsp = svn:eol-style=CRLF\n"
+ "# *.dsw = svn:eol-style=CRLF\n"
+ "# *.sh = svn:eol-style=native;svn:executable\n"
+ "# *.txt = svn:eol-style=native\n"
+ "# *.png = svn:mimetype=image/png\n"
+ "# *.jpg = svn:mimetype=image/jpeg\n"
+ "# Makefile = svn:eol-style=native\n"
+ "\n"
+ "\n"
"### See http://subversion.tigris.org/issues/show_bug.cgi?id=668\n"
"### for what else will soon be customized in this file.\n";
Index: subversion/libsvn_client/client.h
===================================================================
--- subversion/libsvn_client/client.h (revision 7267)
+++ subversion/libsvn_client/client.h (working copy)
@@ -237,6 +237,21 @@
/*** Add/delete ***/
+/* Read automatic properties matching PATH from CTX->config.
+ A hash is returned in *PROPERTIES containing propname/value pairs or
+ when auto-props are disabled *PROPERTIES is set to NULL.
+ *MIMETYPE is set to to the mimetype or to NULL.
+ This function does not create a subpool, the caller is responsible to
+ create one if necessary.
+*/
+svn_error_t *
+svn_client__get_auto_props (apr_hash_t **properties,
+ const char **mimetype,
+ const char *path,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool);
+
+
/* The main logic for client deletion from a working copy. Deletes PATH
from ADM_ACCESS. If PATH (or any item below a directory PATH) is
modified the delete will fail and return an error unless FORCE is TRUE.
Index: subversion/libsvn_client/commit.c
===================================================================
--- subversion/libsvn_client/commit.c (revision 7267)
+++ subversion/libsvn_client/commit.c (working copy)
@@ -106,29 +106,34 @@
{
void *file_baton;
const char *mimetype;
- svn_boolean_t executable;
unsigned char digest[MD5_DIGESTSIZE];
const char *text_checksum;
+ apr_hash_t* properties;
+ apr_hash_index_t *hi;
/* Add the file, using the pool from the FILES hash. */
SVN_ERR (editor->add_file (edit_path, dir_baton, NULL, SVN_INVALID_REVNUM,
pool, &file_baton));
- /* If the file has a discernable mimetype, add that as a property to
- the file. */
- SVN_ERR (svn_io_detect_mimetype (&mimetype, path, pool));
- if (mimetype)
- SVN_ERR (editor->change_file_prop (file_baton, SVN_PROP_MIME_TYPE,
- svn_string_create (mimetype, pool),
+ /* add automatic properties */
+ SVN_ERR (svn_client__get_auto_props (&properties, &mimetype, path, ctx,
pool));
+ if (properties)
+ {
+ for (hi = apr_hash_first (pool, properties);
+ hi != NULL; hi = apr_hash_next (hi))
+ {
+ char *propname;
+ svn_string_t propvalue;
- /* If the file is executable, add that as a property to the file. */
- SVN_ERR (svn_io_is_file_executable (&executable, path, pool));
- if (executable)
- SVN_ERR (editor->change_file_prop (file_baton, SVN_PROP_EXECUTABLE,
- svn_string_create ("", pool),
- pool));
-
+ apr_hash_this (hi, (const void **)&propname, NULL,
+ (void **)&propvalue.data);
+ propvalue.len = strlen (propvalue.data);
+ SVN_ERR (editor->change_file_prop (file_baton, propname,
+ &propvalue, pool));
+ }
+ }
+
if (ctx->notify_func)
(*ctx->notify_func) (ctx->notify_baton,
path,
Index: subversion/libsvn_client/add.c
===================================================================
--- subversion/libsvn_client/add.c (revision 7267)
+++ subversion/libsvn_client/add.c (working copy)
@@ -23,6 +23,7 @@
/*** Includes. ***/
#include <string.h>
+#include <apr_fnmatch.h>
#include "svn_wc.h"
#include "svn_client.h"
#include "svn_string.h"
@@ -30,13 +31,185 @@
#include "svn_error.h"
#include "svn_path.h"
#include "svn_io.h"
+#include "svn_config.h"
#include "client.h"
/*** Code. ***/
+/* This structure is used as baton for enumerating the config entries
+ in the auto-props section.
+*/
+typedef struct
+{
+ /* the file name for which properties are searched */
+ const char *filename;
+
+ /* when this flag is set the hash contains svn:executable */
+ svn_boolean_t have_executable;
+
+ /* when mimetype is not NULL is set the hash contains svn:mime-type */
+ const char *mimetype;
+
+ /* the hash table for storing the property name/value pairs */
+ apr_hash_t *properties;
+
+ /* a pool used for allocating memory */
+ apr_pool_t *pool;
+} auto_props_baton_t;
+
+/* For one auto-props config entry (NAME, VALUE), if the filename pattern
+ NAME matches BATON->filename then add the properties listed in VALUE
+ into BATON->properties. BATON must point to an auto_props_baton_t.
+*/
+static svn_boolean_t
+auto_props_enumerator (const char *name,
+ const char *value,
+ void *baton)
+{
+ auto_props_baton_t *autoprops = baton;
+ char *property;
+ char *last_token;
+ int len;
+
+ /* nothing to do here without a value */
+ if (strlen (value) == 0)
+ return TRUE;
+
+ /* check if filename matches and return if it doesn't */
+ if (apr_fnmatch (name, autoprops->filename, 0) == APR_FNM_NOMATCH)
+ return TRUE;
+
+ /* parse the value */
+ property = apr_pstrdup (autoprops->pool, value);
+ property = apr_strtok (property, ";", &last_token);
+ while (property)
+ {
+ char *value;
+
+ value = strchr (property, '=');
+ if (value)
+ {
+ *value = 0;
+ value++;
+ apr_collapse_spaces (value, value);
+ }
+ else
+ value = "";
+ apr_collapse_spaces (property, property);
+ len = strlen (property);
+ if (len > 0)
+ {
+ apr_hash_set (autoprops->properties, property, len, value );
+ if (strcmp (property, SVN_PROP_MIME_TYPE) == 0)
+ autoprops->mimetype = value;
+ else if (strcmp (property, SVN_PROP_EXECUTABLE) == 0)
+ autoprops->have_executable = TRUE;
+ }
+ property = apr_strtok (NULL, ";", &last_token);
+ }
+ return TRUE;
+}
+
+svn_error_t *
+svn_client__get_auto_props (apr_hash_t **properties,
+ const char **mimetype,
+ const char *path,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ svn_config_t *cfg;
+ const char *cfgvalue;
+ auto_props_baton_t autoprops;
+
+ /* initialisation */
+ autoprops.properties = apr_hash_make (pool);
+ autoprops.filename = svn_path_basename (path, pool);
+ autoprops.pool = pool;
+ autoprops.mimetype = NULL;
+ autoprops.have_executable = FALSE;
+ *properties = autoprops.properties;
+ cfg = apr_hash_get (ctx->config, SVN_CONFIG_CATEGORY_CONFIG,
+ APR_HASH_KEY_STRING);
+
+ /* check that auto props is enabled */
+ svn_config_get (cfg, &cfgvalue, SVN_CONFIG_SECTION_MISCELLANY,
+ SVN_CONFIG_OPTION_ENABLE_AUTO_PROPS, "false");
+ if (strcmp (cfgvalue, "true") == 0)
+ {
+ /* search for auto props */
+ svn_config_enumerate (cfg, SVN_CONFIG_SECTION_AUTO_PROPS,
+ auto_props_enumerator, &autoprops);
+ }
+ /* if mimetype has not been set check the file */
+ if (!autoprops.mimetype)
+ {
+ SVN_ERR (svn_io_detect_mimetype (&autoprops.mimetype, path, pool));
+ if (autoprops.mimetype)
+ apr_hash_set (autoprops.properties, SVN_PROP_MIME_TYPE,
+ strlen (SVN_PROP_MIME_TYPE), autoprops.mimetype );
+ }
+
+ /* if executable has not been set check the file */
+ if (!autoprops.have_executable)
+ {
+ svn_boolean_t executable = FALSE;
+ SVN_ERR (svn_io_is_file_executable (&executable, path, pool));
+ if (executable)
+ apr_hash_set (autoprops.properties, SVN_PROP_EXECUTABLE,
+ strlen (SVN_PROP_EXECUTABLE), "" );
+ }
+
+ *mimetype = autoprops.mimetype;
+ return SVN_NO_ERROR;
+}
+
static svn_error_t *
+add_file (const char *path,
+ svn_client_ctx_t *ctx,
+ svn_wc_adm_access_t *adm_access,
+ apr_pool_t *pool)
+{
+ apr_hash_t* properties;
+ apr_hash_index_t *hi;
+ const char *mimetype;
+
+ /* add the file */
+ SVN_ERR (svn_wc_add (path, adm_access, NULL, SVN_INVALID_REVNUM,
+ ctx->cancel_func, ctx->cancel_baton,
+ NULL, NULL, pool));
+ /* get automatic properties */
+ SVN_ERR (svn_client__get_auto_props (&properties, &mimetype, path, ctx,
+ pool));
+ if (properties)
+ {
+ /* loop through the hashtable and add the properties */
+ for (hi = apr_hash_first (pool, properties);
+ hi != NULL; hi = apr_hash_next (hi))
+ {
+ char *propname;
+ svn_string_t propvalue;
+
+ apr_hash_this (hi, (const void **)&propname, NULL,
+ (void **)&propvalue.data);
+ propvalue.len = strlen (propvalue.data);
+ SVN_ERR (svn_wc_prop_set (propname, &propvalue, path, adm_access,
+ pool));
+ }
+ }
+ /* Report the addition to the caller. */
+ if (ctx->notify_func != NULL)
+ (*ctx->notify_func) (ctx->notify_baton, path, svn_wc_notify_add,
+ svn_node_file,
+ mimetype,
+ svn_wc_notify_state_unknown,
+ svn_wc_notify_state_unknown,
+ SVN_INVALID_REVNUM);
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
add_dir_recursive (const char *dirname,
svn_wc_adm_access_t *adm_access,
svn_client_ctx_t *ctx,
@@ -97,9 +270,7 @@
SVN_ERR (add_dir_recursive (fullpath, dir_access, ctx, subpool));
else if (this_entry.filetype == APR_REG)
- SVN_ERR (svn_wc_add (fullpath, dir_access, NULL, SVN_INVALID_REVNUM,
- ctx->cancel_func, ctx->cancel_baton,
- ctx->notify_func, ctx->notify_baton, subpool));
+ SVN_ERR (add_file (fullpath, ctx, dir_access, subpool));
/* Clean out the per-iteration pool. */
svn_pool_clear (subpool);
@@ -146,6 +317,8 @@
SVN_ERR (svn_io_check_path (path, &kind, pool));
if ((kind == svn_node_dir) && recursive)
err = add_dir_recursive (path, adm_access, ctx, pool);
+ else if (kind == svn_node_file)
+ err = add_file (path, ctx, adm_access, pool);
else
err = svn_wc_add (path, adm_access, NULL, SVN_INVALID_REVNUM,
ctx->cancel_func, ctx->cancel_baton,
Index: subversion/clients/cmdline/cl.h
===================================================================
--- subversion/clients/cmdline/cl.h (revision 7267)
+++ subversion/clients/cmdline/cl.h (working copy)
@@ -68,7 +68,9 @@
svn_cl__editor_cmd_opt,
svn_cl__old_cmd_opt,
svn_cl__new_cmd_opt,
- svn_cl__config_dir_opt
+ svn_cl__config_dir_opt,
+ svn_cl__autoprops_opt,
+ svn_cl__no_autoprops_opt
} svn_cl__longopt_t;
@@ -121,6 +123,8 @@
const char *new_target; /* diff target */
svn_boolean_t relocate; /* rewrite urls (svn switch) */
const char * config_dir; /* over-riding configuration directory */
+ svn_boolean_t autoprops; /* enable automatic properties */
+ svn_boolean_t no_autoprops; /* disable automatic properties */
} svn_cl__opt_state_t;
Index: subversion/clients/cmdline/main.c
===================================================================
--- subversion/clients/cmdline/main.c (revision 7267)
+++ subversion/clients/cmdline/main.c (working copy)
@@ -124,6 +124,10 @@
"relocate via URL-rewriting"},
{"config-dir", svn_cl__config_dir_opt, 1,
"read user configuration files from directory ARG"},
+ {"auto-props", svn_cl__autoprops_opt, 0,
+ "enable automatic properties"},
+ {"no-auto-props", svn_cl__no_autoprops_opt, 0,
+ "disable automatic properties"},
{0, 0, 0, 0}
};
@@ -151,7 +155,8 @@
"Put files and directories under revision control, scheduling\n"
"them for addition to repository. They will be added in next commit.\n"
"usage: add PATH...\n",
- {svn_cl__targets_opt, 'N', 'q', svn_cl__config_dir_opt} },
+ {svn_cl__targets_opt, 'N', 'q', svn_cl__config_dir_opt,
+ svn_cl__autoprops_opt, svn_cl__no_autoprops_opt} },
{ "cat", svn_cl__cat, {0},
"Output the content of specified files or URLs.\n"
@@ -261,7 +266,8 @@
" If PATH is omitted '.' is assumed. Parent directories are created\n"
" as necessary in the repository.\n",
{'m', 'F', 'q', 'N', SVN_CL__AUTH_OPTIONS, svn_cl__force_log_opt,
- svn_cl__editor_cmd_opt, svn_cl__encoding_opt, svn_cl__config_dir_opt} },
+ svn_cl__editor_cmd_opt, svn_cl__encoding_opt, svn_cl__config_dir_opt,
+ svn_cl__autoprops_opt, svn_cl__no_autoprops_opt} },
{ "info", svn_cl__info, {0},
"Display info about a resource.\n"
@@ -843,6 +849,30 @@
svn_path_canonicalize (opt_arg,
pool));
break;
+ case svn_cl__autoprops_opt:
+ if (opt_state.no_autoprops)
+ {
+ err = svn_error_create (SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
+ "--auto-props and --no-auto-props are "
+ "mutually exclusive.");
+ svn_handle_error (err, stderr, FALSE);
+ svn_pool_destroy (pool);
+ return EXIT_FAILURE;
+ }
+ opt_state.autoprops = TRUE;
+ break;
+ case svn_cl__no_autoprops_opt:
+ if (opt_state.autoprops)
+ {
+ err = svn_error_create (SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
+ "--auto-props and --no-auto-props are "
+ "mutually exclusive.");
+ svn_handle_error (err, stderr, FALSE);
+ svn_pool_destroy (pool);
+ return EXIT_FAILURE;
+ }
+ opt_state.no_autoprops = TRUE;
+ break;
default:
/* Hmmm. Perhaps this would be a good place to squirrel away
opts that commands like svn diff might need. Hmmm indeed. */
@@ -995,6 +1025,22 @@
svn_config_set (cfg, SVN_CONFIG_SECTION_HELPERS,
SVN_CONFIG_OPTION_DIFF3_CMD, opt_state.merge_cmd);
+ /* Update auto-props-enable option for add/import commands */
+ if (subcommand->cmd_func == svn_cl__add
+ || subcommand->cmd_func == svn_cl__import)
+ {
+ if (opt_state.autoprops)
+ {
+ svn_config_set (cfg, SVN_CONFIG_SECTION_MISCELLANY,
+ SVN_CONFIG_OPTION_ENABLE_AUTO_PROPS, "true");
+ }
+ if (opt_state.no_autoprops)
+ {
+ svn_config_set (cfg, SVN_CONFIG_SECTION_MISCELLANY,
+ SVN_CONFIG_OPTION_ENABLE_AUTO_PROPS, "false");
+ }
+ }
+
/* Set the log message callback function. Note that individual
subcommands will populate the ctx.log_msg_baton */
ctx.log_msg_func = svn_cl__get_log_message;
Index: subversion/tests/clients/cmdline/autoprop_tests.py
===================================================================
--- subversion/tests/clients/cmdline/autoprop_tests.py (revision 0)
+++ subversion/tests/clients/cmdline/autoprop_tests.py (revision 0)
@@ -0,0 +1,422 @@
+#!/usr/bin/env python
+#
+# autoprop_tests.py: testing automatic properties
+#
+# Subversion is a tool for revision control.
+# See http://subversion.tigris.org for more information.
+#
+# ====================================================================
+# Copyright (c) 2000-2003 CollabNet. All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://subversion.tigris.org/license-1.html.
+# If newer versions of this license are posted there, you may use a
+# newer version instead, at your option.
+#
+######################################################################
+
+# General modules
+import string, sys, re, os, os.path, shutil
+
+# Our testing module
+import svntest
+
+
+# (abbreviation)
+Skip = svntest.testcase.Skip
+XFail = svntest.testcase.XFail
+Item = svntest.wc.StateItem
+
+
+# Helper functions
+def check_prop(name, path, exp_out):
+ """Verify that property NAME on PATH has a value of EXP_OUT"""
+ # Not using run_svn because binary_mode must be set
+ out, err = svntest.main.run_svn(None, 'pg', '--strict', name, path)
+ if out != exp_out:
+ print "Expected standard output: ", exp_out, "\n"
+ print "Actual standard output: ", out, "\n"
+ raise svntest.Failure
+
+
+def check_proplist(path, exp_out):
+ """Verify that property NAME on PATH has a value of EXP_OUT"""
+ # Not using run_svn because binary_mode must be set
+ out, err = svntest.main.run_svn(None, 'proplist', path)
+ if len(out) == 0 and len(exp_out) == 0:
+ # no properties expected and svn didn't output anything so it's ok
+ return
+
+ if len(out) < 1:
+ print "Expected result: ", exp_out, "\n"
+ print "Actual standard output: ", out, "\n"
+ raise svntest.Failure
+ out2 = []
+ if len(out) > 1:
+ for line in out[1:]:
+ out2 = out2 + [string.strip(line)]
+ out2.sort()
+ exp_out.sort()
+ if out2 != exp_out:
+ print "Expected result: ", exp_out, "\n"
+ print "Actual result: ", out2, "\n"
+ print "Actual standard output: ", out, "\n"
+ raise svntest.Failure
+
+
+######################################################################
+# Tests
+
+#----------------------------------------------------------------------
+
+def create_config(config_dir, enable_flag):
+ "create config directories and files"
+
+ # config file names
+ cfgfile_cfg = os.path.join(config_dir, 'config')
+ cfgfile_srv = os.path.join(config_dir, 'server')
+
+ # create the directory
+ if not os.path.isdir(config_dir):
+ os.makedirs(config_dir)
+
+ # create the file 'config'
+ fd = open(cfgfile_cfg, 'w')
+ fd.write('[miscellany]\n')
+ fd.write('enable-auto-props = ' + enable_flag + '\n')
+ fd.write('\n')
+ fd.write('[auto-props]\n')
+ fd.write('*.c = cfile=yes\n')
+ fd.write('*.jpg = jpgfile=ja\n')
+ fd.write('fubar* = tarfile=si\n')
+ fd.write('foobar.lha = lhafile=da;lzhfile=niet\n')
+ fd.write('* = auto=oui\n')
+ fd.write('\n')
+ fd.close()
+
+ # create the file 'server'
+ fd = open(cfgfile_srv, 'w')
+ fd.write('#\n')
+ fd.close()
+
+
+#----------------------------------------------------------------------
+
+def create_test_file(dir, name):
+ "create a test file"
+
+ fd = open(os.path.join(dir, name), 'w', 0644)
+ fd.write('foo\nbar\nbaz\n')
+ fd.close()
+
+#----------------------------------------------------------------------
+
+def autoprops_test(sbox, cmd, cfgtype, paramtype, subdir):
+ """configurable autoprops test.
+ if CMD == 1 do test svn import else test svn add
+ if CFGTYPE == 1 add is enabled in the config, if it is 2 import is
+ enabled else both are disabled
+ if PARAMTYPE == 1 --auto-props is added to the commandline, if it is
+ 2 --no-auto-props is added else none is added
+ if string SUBDIR is not empty files are created in that subdir and the
+ directory is added/imported"""
+
+ # some directories
+ wc_dir = sbox.wc_dir
+ tmp_dir = os.path.abspath(svntest.main.temp_dir)
+ config_dir = os.path.join(tmp_dir, 'autoprops_config')
+ repos_url = svntest.main.current_repo_url
+ svntest.main.set_config_dir(config_dir)
+
+ # initialize parameters
+ parameters = []
+
+ # add svn command
+ if cmd == 1:
+ parameters = parameters + ['import', '--username', main.wc_author,
+ '--password', main.wc_passwd, '-m', 'bla']
+ need_svn_up = 1
+ files_dir = tmp_dir
+ else:
+ parameters = parameters + ['add']
+ need_svn_up = 0
+ files_dir = wc_dir
+ parameters = parameters + ['--config-dir', config_dir]
+
+ # set config flags
+ if cfgtype == 1:
+ create_config(config_dir, 'true')
+ enable_flag = 1
+ else:
+ create_config(config_dir, 'false')
+ enable_flag = 0
+
+ # add comandline flags
+ if paramtype == 1:
+ parameters = parameters + ['--auto-props']
+ enable_flag = 1
+ elif paramtype == 2:
+ parameters = parameters + ['--no-auto-props']
+ enable_flag = 0
+
+ # setup subdirectory if needed
+ if len(subdir) > 0:
+ files_dir = os.path.join(files_dir, subdir)
+ files_wc_dir = os.path.join(wc_dir, subdir)
+ os.makedirs(files_dir)
+ else:
+ files_wc_dir = wc_dir
+
+ # create test files
+ filenames = []
+ filenames = filenames + ['foo.h']
+ create_test_file(files_dir, filenames[len(filenames)-1])
+ filenames = filenames + ['foo.c']
+ create_test_file(files_dir, filenames[len(filenames)-1])
+ filenames = filenames + ['foo.jpg']
+ create_test_file(files_dir, filenames[len(filenames)-1])
+ filenames = filenames + ['fubar.tar']
+ create_test_file(files_dir, filenames[len(filenames)-1])
+ filenames = filenames + ['foobar.lha']
+ create_test_file(files_dir, filenames[len(filenames)-1])
+
+ if len(subdir) == 0:
+ # add/import the files
+ for filename in filenames:
+ filename = os.path.join(files_dir, filename)
+ if cmd == 1:
+ tmp_params = parameters + [filename, os.path.join(repos_url, filename)]
+ else:
+ tmp_params = parameters + [filename]
+ svntest.main.run_svn(None, *tmp_params)
+ else:
+ # add/import subdirectory
+ if cmd == 1:
+ parameters = parameters + [files_dir, repos_url]
+ else:
+ parameters = parameters + [files_wc_dir]
+ svntest.main.run_svn(None, *parameters)
+
+ # do an svn up if needed
+ if need_svn_up:
+ svntest.main.run_svn(None, 'update')
+
+ # check the properties
+ if enable_flag:
+ filename = os.path.join(files_wc_dir, 'foo.h' )
+ check_proplist(filename,['auto'])
+ check_prop('auto', filename, ['oui'])
+ filename = os.path.join(files_wc_dir, 'foo.c' )
+ check_proplist(filename,['cfile', 'auto'])
+ check_prop('auto', filename, ['oui'])
+ check_prop('cfile', filename, ['yes'])
+ filename = os.path.join(files_wc_dir, 'foo.jpg' )
+ check_proplist(filename,['jpgfile', 'auto'])
+ check_prop('auto', filename, ['oui'])
+ check_prop('jpgfile', filename, ['ja'])
+ filename = os.path.join(files_wc_dir, 'fubar.tar' )
+ check_proplist(filename,['tarfile', 'auto'])
+ check_prop('auto', filename, ['oui'])
+ check_prop('tarfile', filename, ['si'])
+ filename = os.path.join(files_wc_dir, 'foobar.lha' )
+ check_proplist(filename,['lhafile', 'lzhfile', 'auto'])
+ check_prop('auto', filename, ['oui'])
+ check_prop('lhafile', filename, ['da'])
+ check_prop('lzhfile', filename, ['niet'])
+ else:
+ filename = os.path.join(files_wc_dir, 'foo.h' )
+ check_proplist(filename,[])
+ filename = os.path.join(files_wc_dir, 'foo.c' )
+ check_proplist(filename,[])
+ filename = os.path.join(files_wc_dir, 'foo.jpg' )
+ check_proplist(filename,[])
+ filename = os.path.join(files_wc_dir, 'fubar.tar' )
+ check_proplist(filename,[])
+ filename = os.path.join(files_wc_dir, 'foobar.lha' )
+ check_proplist(filename,[])
+
+
+#----------------------------------------------------------------------
+
+def autoprops_add_no_none(sbox):
+ "add: config=no, commandline=none"
+
+ # Bootstrap
+ sbox.build()
+
+ # cmd=add, config=no, commandline=none
+ autoprops_test(sbox, 'add', 0, 0, '')
+
+#----------------------------------------------------------------------
+
+def autoprops_add_yes_none(sbox):
+ "add: config=yes, commandline=none"
+
+ # Bootstrap
+ sbox.build()
+
+ # cmd=add, config=yes, commandline=none
+ autoprops_test(sbox, 'add', 1, 0, '')
+
+#----------------------------------------------------------------------
+
+def autoprops_add_no_yes(sbox):
+ "add: config=no, commandline=yes"
+
+ # Bootstrap
+ sbox.build()
+
+ # cmd=add, config=no, commandline=yes
+ autoprops_test(sbox, 'add', 0, 1, '')
+
+#----------------------------------------------------------------------
+
+def autoprops_add_yes_yes(sbox):
+ "add: config=yes, commandline=yes"
+
+ # Bootstrap
+ sbox.build()
+
+ # cmd=add, config=yes, commandline=yes
+ autoprops_test(sbox, 'add', 1, 1, '')
+
+#----------------------------------------------------------------------
+
+def autoprops_add_no_no(sbox):
+ "add: config=no, commandline=no"
+
+ # Bootstrap
+ sbox.build()
+
+ # cmd=add, config=no, commandline=no
+ autoprops_test(sbox, 'add', 0, 2, '')
+
+#----------------------------------------------------------------------
+
+def autoprops_add_yes_no(sbox):
+ "add: config=yes, commandline=no"
+
+ # Bootstrap
+ sbox.build()
+
+ # cmd=add, config=yes, commandline=no
+ autoprops_test(sbox, 'add', 1, 2, '')
+
+#----------------------------------------------------------------------
+
+def autoprops_imp_no_none(sbox):
+ "import: config=no, commandline=none"
+
+ # Bootstrap
+ sbox.build()
+
+ # cmd=import, config=no, commandline=none
+ autoprops_test(sbox, 'import', 0, 0, '')
+
+#----------------------------------------------------------------------
+
+def autoprops_imp_yes_none(sbox):
+ "import: config=yes, commandline=none"
+
+ # Bootstrap
+ sbox.build()
+
+ # cmd=import, config=yes, commandline=none
+ autoprops_test(sbox, 'import', 1, 0, '')
+
+#----------------------------------------------------------------------
+
+def autoprops_imp_no_yes(sbox):
+ "import: config=no, commandline=yes"
+
+ # Bootstrap
+ sbox.build()
+
+ # cmd=import, config=no, commandline=yes
+ autoprops_test(sbox, 'import', 0, 1, '')
+
+#----------------------------------------------------------------------
+
+def autoprops_imp_yes_yes(sbox):
+ "import: config=yes, commandline=yes"
+
+ # Bootstrap
+ sbox.build()
+
+ # cmd=import, config=yes, commandline=yes
+ autoprops_test(sbox, 'import', 1, 1, '')
+
+#----------------------------------------------------------------------
+
+def autoprops_imp_no_no(sbox):
+ "import: config=no, commandline=no"
+
+ # Bootstrap
+ sbox.build()
+
+ # cmd=import, config=no, commandline=no
+ autoprops_test(sbox, 'import', 0, 2, '')
+
+#----------------------------------------------------------------------
+
+def autoprops_imp_yes_no(sbox):
+ "import: config=yes, commandline=no"
+
+ # Bootstrap
+ sbox.build()
+
+ # cmd=import, config=yes, commandline=no
+ autoprops_test(sbox, 'import', 1, 2, '')
+
+#----------------------------------------------------------------------
+
+def autoprops_add_dir(sbox):
+ "add directory"
+
+ # Bootstrap
+ sbox.build()
+
+ # cmd=import, config=yes, commandline=no
+ autoprops_test(sbox, 'add', 1, 0, 'autodir')
+
+#----------------------------------------------------------------------
+
+def autoprops_imp_dir(sbox):
+ "import directory"
+
+ # Bootstrap
+ sbox.build()
+
+ # cmd=import, config=yes, commandline=no
+ autoprops_test(sbox, 'import', 1, 0, 'autodir')
+
+
+########################################################################
+# Run the tests
+
+
+# list all tests here, starting with None:
+test_list = [ None,
+ autoprops_add_no_none,
+ autoprops_add_yes_none,
+ autoprops_add_no_yes,
+ autoprops_add_yes_yes,
+ autoprops_add_no_no,
+ autoprops_add_yes_no,
+ autoprops_imp_no_none,
+ autoprops_imp_yes_none,
+ autoprops_imp_no_yes,
+ autoprops_imp_yes_yes,
+ autoprops_imp_no_no,
+ autoprops_imp_yes_no,
+ autoprops_add_dir,
+ autoprops_imp_dir,
+ ]
+
+if __name__ == '__main__':
+ svntest.main.run_tests(test_list)
+ # NOTREACHED
+
+
+### End of file.
Property changes on: subversion/tests/clients/cmdline/autoprop_tests.py
___________________________________________________________________
Name: svn:executable
+ *
Index: subversion/tests/clients/cmdline/svntest/main.py
===================================================================
--- subversion/tests/clients/cmdline/svntest/main.py (revision 7267)
+++ subversion/tests/clients/cmdline/svntest/main.py (working copy)
@@ -127,6 +127,7 @@
pristine_dir = os.path.join(temp_dir, "repos")
greek_dump_dir = os.path.join(temp_dir, "greekfiles")
config_dir = os.path.abspath(os.path.join(temp_dir, "config"))
+default_config_dir = config_dir
#
@@ -226,6 +227,20 @@
return stdout_lines, stderr_lines
+def set_config_dir(cfgdir):
+ "Set the config directory."
+
+ global config_dir
+ config_dir = cfgdir
+
+def reset_config_dir():
+ "Reset the config directory to the default value."
+
+ global config_dir
+ global default_config_dir
+
+ config_dir = default_config_dir
+
# For running subversion and returning the output
def run_svn(error_expected, *varargs):
"""Run svn with VARARGS; return stdout, stderr as lists of lines.
@@ -442,6 +457,7 @@
exit_code = tc.run(args)
if sandbox is not None and not exit_code and cleanup_mode:
sandbox.cleanup_test_paths()
+ reset_config_dir()
return exit_code
def _internal_run_tests(test_list, testnum=None):
----- end of auto-props patch -----
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Thu Oct 2 05:11:43 2003