Index: subversion/include/svn_types.h =================================================================== --- subversion/include/svn_types.h (revision 15177) +++ subversion/include/svn_types.h (working copy) @@ -188,7 +188,45 @@ svn_recursive }; +/** Added loc information with exiting directory entry. */ +typedef struct svn_dirent2_t +{ + /** node kind */ + svn_node_kind_t kind; + /** length of file text, or 0 for directories */ + svn_filesize_t size; + + /** does the node have props? */ + svn_boolean_t has_props; + + /** last rev in which this node changed */ + svn_revnum_t created_rev; + + /** time of created_rev (mod-time) */ + apr_time_t time; + + /** author of created_rev */ + const char *last_author; + + /** lock token or NULL if path not locked in this REPOS */ + const char *lock_token; + + /** lock owner, or NULL if not locked in this REPOS */ + const char *lock_owner; + + /** lock comment or NULL if not locked in this REPOS or no comment */ + const char *lock_comment; + + /** Lock creation date or 0 if not locked in this REPOS */ + apr_time_t lock_creation_date; + + /** Lock expiration date or 0 if not locked in this REPOS */ + apr_time_t lock_expiration_date; + +} svn_dirent2_t; + + /** A general subversion directory entry. */ typedef struct svn_dirent_t { Index: subversion/include/svn_client.h =================================================================== --- subversion/include/svn_client.h (revision 15177) +++ subversion/include/svn_client.h (working copy) @@ -1797,31 +1797,46 @@ svn_client_ctx_t *ctx, apr_pool_t *pool); - /** - * Set @a *dirents to a newly allocated hash of entries for @a - * path_or_url at @a revision. The actual node revision selected is + * Set @a *dirents to a newly allocated hash of entries with lock information + * for @a path_or_url at @a revision. The actual node revision selected is * determined by the path as it exists in @a peg_revision. If @a * peg_revision is @c svn_opt_revision_unspecified, then it defaults * to @c svn_opt_revision_head for URLs or @c svn_opt_revision_working * for WC targets. * * If @a path_or_url is a directory, return all dirents in the hash. If - * @a path_or_url is a file, return only the dirent for the file. If @a - * path_or_url is non-existent, return @c SVN_ERR_FS_NOT_FOUND. + * @a path_or_url is a file, return the dirent and lock details for the file. + * If @a path_or_url is non-existent, return @c SVN_ERR_FS_NOT_FOUND. * - * The hash maps entry names (const char *) to @c svn_dirent_t *'s. + * The hash maps entry names (const char *) to @c svn_dirent2_t *'s. * Do all allocation in @a pool. * - * Use authentication baton cached in @a ctx to authenticate against the + * Use authentication baton cached in @a ctx to authenticate against the * repository. * * If @a recurse is true (and @a path_or_url is a directory) this will * be a recursive operation. * - * @since New in 1.2. + * @since New in 1.3. */ svn_error_t * +svn_client_ls3 (apr_hash_t **dirents, + const char *path_or_url, + const svn_opt_revision_t *peg_revision, + const svn_opt_revision_t *revision, + svn_boolean_t recurse, + svn_client_ctx_t *ctx, + apr_pool_t *pool); + +/** + * Similar to svn_client_ls3() except that the allocated hash of entries + * will contain only dirent and the hash maps entry names + * (const char *) to @c svn_dirent_t *'s. + * + * @deprecated Provided for backward compatibility with the 1.2 API. + */ +svn_error_t * svn_client_ls2 (apr_hash_t **dirents, const char *path_or_url, const svn_opt_revision_t *peg_revision, Index: subversion/libsvn_client/ls.c =================================================================== --- subversion/libsvn_client/ls.c (revision 15177) +++ subversion/libsvn_client/ls.c (working copy) @@ -36,7 +36,6 @@ apr_pool_t *pool) { apr_hash_t *tmpdirents; - svn_dirent_t *the_ent; apr_hash_index_t *hi; /* Get the directory's entries, but not its props. */ @@ -53,16 +52,29 @@ const char *path; const void *key; void *val; + svn_lock_t *lock; + svn_dirent2_t *lsent = apr_pcalloc (pool, sizeof(svn_dirent2_t)); apr_hash_this (hi, &key, NULL, &val); - the_ent = val; + memcpy (lsent, val, sizeof (svn_dirent_t)); + + /* Get base name lock information. */ + SVN_ERR (svn_ra_get_lock (ra_session, &lock, key, pool)); + if (lock) + { + lsent->lock_token = lock->token; + lsent->lock_owner = lock->owner; + lsent->lock_comment = lock->comment; + lsent->lock_creation_date = lock->creation_date; + lsent->lock_expiration_date = lock->expiration_date; + } path = svn_path_join (dir, key, pool); - apr_hash_set (dirents, path, APR_HASH_KEY_STRING, val); + apr_hash_set (dirents, path, APR_HASH_KEY_STRING, lsent); - if (recurse && the_ent->kind == svn_node_dir) + if (recurse && lsent->kind == svn_node_dir) SVN_ERR (get_dir_contents (dirents, path, rev, ra_session, recurse, ctx, pool)); } @@ -71,6 +83,87 @@ } svn_error_t * +svn_client_ls3 (apr_hash_t **dirents, + const char *path_or_url, + const svn_opt_revision_t *peg_revision, + const svn_opt_revision_t *revision, + svn_boolean_t recurse, + svn_client_ctx_t *ctx, + apr_pool_t *pool) +{ + svn_ra_session_t *ra_session; + svn_revnum_t rev; + svn_node_kind_t url_kind; + const char *url; + + /* Get an RA plugin for this filesystem object. */ + SVN_ERR (svn_client__ra_session_from_path (&ra_session, &rev, + &url, path_or_url, peg_revision, + revision, ctx, pool)); + + /* Decide if the URL is a file or directory. */ + SVN_ERR (svn_ra_check_path (ra_session, "", rev, &url_kind, pool)); + + if (url_kind == svn_node_dir) + { + *dirents = apr_hash_make (pool); + + SVN_ERR (get_dir_contents (*dirents, "", rev, ra_session, recurse, + ctx, pool)); + } + else if (url_kind == svn_node_file) + { + apr_hash_t *parent_ents; + const char *parent_url, *base_name; + svn_dirent_t *the_ent; + svn_dirent2_t *ls_ent = apr_pcalloc (pool, sizeof(svn_dirent2_t)); + svn_lock_t *lock; + + /* Re-open the session to the file's parent instead. */ + svn_path_split (url, &parent_url, &base_name, pool); + /* 'base_name' is now the last component of an URL, but we want + to use it as a plain file name. Therefore, we must URI-decode + it. */ + base_name = svn_path_uri_decode(base_name, pool); + SVN_ERR (svn_client__open_ra_session_internal (&ra_session, parent_url, + NULL, NULL, NULL, FALSE, + TRUE, ctx, pool)); + + /* Get all parent's entries, no props. */ + SVN_ERR (svn_ra_get_dir (ra_session, "", rev, &parent_ents, + NULL, NULL, pool)); + + /* Get base name lock information. */ + SVN_ERR (svn_ra_get_lock (ra_session, &lock, base_name, pool)); + + /* Copy the relevant entry into the caller's hash. */ + *dirents = apr_hash_make (pool); + the_ent = apr_hash_get (parent_ents, base_name, APR_HASH_KEY_STRING); + if (the_ent == NULL) + return svn_error_createf (SVN_ERR_FS_NOT_FOUND, NULL, + _("URL '%s' non-existent in that revision"), + url); + memcpy (ls_ent, the_ent, sizeof (svn_dirent_t)); + if (lock) + { + ls_ent->lock_token = lock->token; + ls_ent->lock_owner = lock->owner; + ls_ent->lock_comment = lock->comment; + ls_ent->lock_creation_date = lock->creation_date; + ls_ent->lock_expiration_date = lock->expiration_date; + } + + apr_hash_set (*dirents, base_name, APR_HASH_KEY_STRING, ls_ent); + } + else + return svn_error_createf (SVN_ERR_FS_NOT_FOUND, NULL, + _("URL '%s' non-existent in that revision"), + url); + + return SVN_NO_ERROR; +} + +svn_error_t * svn_client_ls2 (apr_hash_t **dirents, const char *path_or_url, const svn_opt_revision_t *peg_revision, Index: subversion/clients/cmdline/ls-cmd.c =================================================================== --- subversion/clients/cmdline/ls-cmd.c (revision 15177) +++ subversion/clients/cmdline/ls-cmd.c (working copy) @@ -50,7 +50,7 @@ for (i = 0; i < array->nelts; ++i) { const char *utf8_entryname; - svn_dirent_t *dirent; + svn_dirent2_t *dirent; svn_sort__item_t *item; svn_pool_clear (subpool); @@ -70,8 +70,8 @@ apr_time_exp_t exp_time; apr_status_t apr_err; apr_size_t size; - char timestr[20]; - const char *sizestr, *utf8_timestr; + char timestr[20], lock_timestr[20]; + const char *sizestr, *utf8_timestr, *utf8_lock_timestr; /* svn_time_to_human_cstring gives us something *way* too long to use for this, so we have to roll our own. We include @@ -98,13 +98,42 @@ sizestr = apr_psprintf (subpool, "%" SVN_FILESIZE_T_FMT, dirent->size); + if (dirent->lock_owner) + { + apr_time_exp_lt (&exp_time, dirent->lock_creation_date); + if (apr_time_sec + (now - dirent->lock_creation_date) < (365 * 86400 / 2) + && apr_time_sec + (dirent->lock_creation_date - now) < (365 * 86400 / 2)) + { + apr_err = apr_strftime (lock_timestr, &size, + sizeof (lock_timestr), + "%b %d %H:%M", &exp_time); + } + else + { + apr_err = apr_strftime (lock_timestr, &size, + sizeof (timestr), + "%b %d %Y", &exp_time); + } + /* if that failed, just zero out the string and print nothing */ + if (apr_err) + lock_timestr[0] = '\0'; + + /* we need it in UTF-8. */ + SVN_ERR (svn_utf_cstring_to_utf8 + (&utf8_lock_timestr, lock_timestr, subpool)); + } + SVN_ERR (svn_cmdline_printf - (subpool, "%7ld %-8.8s %10s %12s %s%s\n", + (subpool, "%7ld %-12s %10s %12s %12s %-12s %s%s\n", dirent->created_rev, dirent->last_author ? dirent->last_author : " ? ", (dirent->kind == svn_node_file) ? sizestr : "", utf8_timestr, + dirent->lock_owner ? utf8_lock_timestr : "", + dirent->lock_owner ? dirent->lock_owner : "", utf8_entryname, (dirent->kind == svn_node_dir) ? "/" : "")); } @@ -322,7 +351,7 @@ /* Get peg revisions. */ SVN_ERR (svn_opt_parse_path (&peg_revision, &truepath, target, subpool)); - SVN_ERR (svn_client_ls2 (&dirents, truepath, &peg_revision, + SVN_ERR (svn_client_ls3 (&dirents, truepath, &peg_revision, &(opt_state->start_revision), opt_state->recursive, ctx, subpool)); Index: subversion/clients/cmdline/main.c =================================================================== --- subversion/clients/cmdline/main.c (revision 15177) +++ subversion/clients/cmdline/main.c (working copy) @@ -379,12 +379,14 @@ "current\n" " working directory.\n" "\n" - " With --verbose, the following fields show the status of the item:\n" + " With --verbose, the following fields will be shown for each item:\n" "\n" " Revision number of the last commit\n" " Author of the last commit\n" " Size (in bytes)\n" - " Date and time of the last commit\n"), + " Date and time of the last commit\n" + " Date and time of the lock creation\n" + " Owner of the lock\n"), {'r', 'v', 'R', svn_cl__incremental_opt, svn_cl__xml_opt, SVN_CL__AUTH_OPTIONS, svn_cl__config_dir_opt} },