Hi stsp! Attaching a patch showing a suggestion on how to split up patch_target_t. Maybe you have some insights on this, before I rush out and start grooking around and making changes to your design.
What 'svn patch' does ---------------------- 1) Match hunks 2) Apply hunks to a stream backed up by a tmp file 3) Install. copy the tmp file to the target location 4) Notify the user on what has happened, e.g. fuzz, offset and rejects The problem ------------- Each property is essentially like it's own text file. 'svn patch' must be generic enough to be able to perform the above actions on both properties and texts. Alternatives -------------- * Simplify. Don't use the unidiff format but just copy the content straight off and apply it. * Duplicate. Create special code for handling props, e.g. have both match_hunk() and match_property_hunk() and so on. Proposed solution ------------------- Use patch_target_t as a container for sub-patch_targets that can be either file-text or a property. Store tree change info needed for step 3) installing and step 4) notifying. Use patch_target_stream_t for step 1) matching and step 2) applying. It should contain streams to the property or text target and the hunks associated with the specific file/property. A scratch log message (the attached patch only contains changes to the structs): * subversion/libsvn_client/patch.c (patch_target_stream_t): New. A struct used for handling the match and apply step of 'svn patch'. It can be either associated with the content of a file or a property. (patch_target_t): Move some fields to patch_target_stream_t and introduce it as a new field. (get_hunk_info, scan_for_match, match_hunk): These funcs makes up step 1) matching. Use patch_target_stream_t instead of patch_target_t. (apply_hunk, reject_hunk): These funcs makes up step 2) applying. Use patch_target_stream_t instead of patch_target_t. (init_patch_target): Create the patch_target_stream_t objects. (apply_one_patch): Loop through the available property hunks in the patch and do step 1) matching. Loop through the property hunks in the patch and do step 2) applying. (...): More things to do. Cheers, Daniel
Index: subversion/libsvn_client/patch.c =================================================================== --- subversion/libsvn_client/patch.c (revision 956349) +++ subversion/libsvn_client/patch.c (arbetskopia) @@ -61,28 +61,14 @@ typedef struct { int fuzz; } hunk_info_t; +/* ### Better naming. This struct contains streams and hunks associated with + * ### a target, be it a file or a property of a file. sub_patch_target_t?`*/ typedef struct { - /* The patch being applied. */ - const svn_patch_t *patch; - /* The target path as it appeared in the patch file, - * but in canonicalised form. */ - const char *canon_path_from_patchfile; + /* The name of the property associated with this 'stream' or NULL if it's + * a text 'stream'. */ + const char *prop_name; - /* The target path, relative to the working copy directory the - * patch is being applied to. A patch strip count applies to this - * and only this path. This is never NULL. */ - const char *local_relpath; - - /* The absolute path of the target on the filesystem. - * Any symlinks the path from the patch file may contain are resolved. - * Is not always known, so it may be NULL. */ - char *local_abspath; - - /* The target file, read-only, seekable. This is NULL in case the target - * file did not exist prior to patch application. */ - apr_file_t *file; - /* A stream to read lines form the target file. This is NULL in case * the target file did not exist prior to patch application. */ svn_stream_t *stream; @@ -100,13 +86,6 @@ typedef struct { /* Path to the temporary file underlying the result stream. */ const char *patched_path; - /* The reject stream, write-only, not seekable. - * Hunks that are rejected will be written to this stream. */ - svn_stream_t *reject; - - /* Path to the temporary file underlying the reject stream. */ - const char *reject_path; - /* The line last read from the target file. */ svn_linenum_t current_line; @@ -119,13 +98,48 @@ typedef struct { * last line read from the target file was using. */ const char *eol_str; + /* True if end-of-file was reached while reading from the target. */ + svn_boolean_t eof; + + /* An array containing hunk_info_t structures for hunks already matched. */ + apr_array_header_t *hunks; + +} patch_target_stream_t; + + +typedef struct { + /* The patch being applied. */ + const svn_patch_t *patch; + + /* The target path as it appeared in the patch file, + * but in canonicalised form. */ + const char *canon_path_from_patchfile; + + /* The target path, relative to the working copy directory the + * patch is being applied to. A patch strip count applies to this + * and only this path. This is never NULL. */ + const char *local_relpath; + + /* The absolute path of the target on the filesystem. + * Any symlinks the path from the patch file may contain are resolved. + * Is not always known, so it may be NULL. */ + char *local_abspath; + + /* The target file, read-only, seekable. This is NULL in case the target + * file did not exist prior to patch application. */ + apr_file_t *file; + + /* The reject stream, write-only, not seekable. + * Hunks that are rejected will be written to this stream. */ + svn_stream_t *reject; + + /* Path to the temporary file underlying the reject stream. */ + const char *reject_path; + /* An array containing stream markers marking the beginning * each line in the target stream. */ apr_array_header_t *lines; - /* An array containing hunk_info_t structures for hunks already matched. */ - apr_array_header_t *hunks; - /* The node kind of the target as found in WC-DB prior * to patch application. */ svn_node_kind_t db_kind; @@ -136,9 +150,6 @@ typedef struct { /* True if the target was locally deleted prior to patching. */ svn_boolean_t locally_deleted; - /* True if end-of-file was reached while reading from the target. */ - svn_boolean_t eof; - /* True if the target had to be skipped for some reason. */ svn_boolean_t skipped; @@ -169,6 +180,14 @@ typedef struct { /* The keywords of the target. */ apr_hash_t *keywords; + /* The streams for the file. + * ### C'mon the naming and doc strings suck.. */ + patch_target_stream_t *file_stream; + + /* An array containing patch_target_stream_t * objects for properties. + * ### .. This one sucks too. */ + apr_array_header_t *property_streams; + /* The pool the target is allocated in. */ apr_pool_t *pool; } patch_target_t;