@@ -34,10 +34,128 @@ static int write_oid(const struct object_id *oid,
3434 return 0 ;
3535}
3636
37+ /*
38+ * Go through all .promisor files contained in repo (excluding those whose name
39+ * appears in not_repacked_basenames, which acts as a ignorelist), and copies
40+ * their content inside the destination file "<packtmp>-<dest_hex>.promisor".
41+ * Each line of a never repacked .promisor file is: "<oid> <ref>" (as described
42+ * in the write_promisor_file() function).
43+ * After a repack, the copied lines will be: "<oid> <ref> <time>", where <time>
44+ * is the time (in Unix time) at which the .promisor file was last modified.
45+ * Only the lines whose <oid> is present inside "<packtmp>-<dest_hex>.idx" will
46+ * be copied.
47+ * The contents of all .promisor files are assumed to be correctly formed.
48+ */
49+ static void copy_promisor_content (struct repository * repo ,
50+ const char * dest_hex ,
51+ const char * packtmp ,
52+ struct strset * not_repacked_basenames )
53+ {
54+ char * dest_idx_name ;
55+ char * dest_promisor_name ;
56+ FILE * dest ;
57+ struct strset dest_content = STRSET_INIT ;
58+ struct strbuf dest_to_write = STRBUF_INIT ;
59+ struct strbuf source_promisor_name = STRBUF_INIT ;
60+ struct strbuf line = STRBUF_INIT ;
61+ struct object_id dest_oid ;
62+ struct packed_git * dest_pack , * p ;
63+ int err ;
64+
65+ dest_idx_name = mkpathdup ("%s-%s.idx" , packtmp , dest_hex );
66+ get_oid_hex_algop (dest_hex , & dest_oid , repo -> hash_algo );
67+ dest_pack = parse_pack_index (repo , dest_oid .hash , dest_idx_name );
68+
69+ /* Open the .promisor dest file, and fill dest_content with its content */
70+ dest_promisor_name = mkpathdup ("%s-%s.promisor" , packtmp , dest_hex );
71+ dest = xfopen (dest_promisor_name , "r+" );
72+ while (strbuf_getline (& line , dest ) != EOF )
73+ strset_add (& dest_content , line .buf );
74+
75+ repo_for_each_pack (repo , p ) {
76+ FILE * source ;
77+ struct stat source_stat ;
78+
79+ if (!p -> pack_promisor )
80+ continue ;
81+
82+ if (not_repacked_basenames &&
83+ strset_contains (not_repacked_basenames , pack_basename (p )))
84+ continue ;
85+
86+ strbuf_reset (& source_promisor_name );
87+ strbuf_addstr (& source_promisor_name , p -> pack_name );
88+ strbuf_strip_suffix (& source_promisor_name , ".pack" );
89+ strbuf_addstr (& source_promisor_name , ".promisor" );
90+
91+ if (stat (source_promisor_name .buf , & source_stat ))
92+ die (_ ("File not found: %s" ), source_promisor_name .buf );
93+
94+ source = xfopen (source_promisor_name .buf , "r" );
95+
96+ while (strbuf_getline (& line , source ) != EOF ) {
97+ struct string_list line_sections = STRING_LIST_INIT_DUP ;
98+ struct object_id oid ;
99+
100+ /* Split line into <oid>, <ref> and <time> (if <time> exists) */
101+ string_list_split (& line_sections , line .buf , " " , 3 );
102+
103+ /* Ignore the lines where <oid> doesn't appear in the dest_pack */
104+ get_oid_hex_algop (line_sections .items [0 ].string , & oid , repo -> hash_algo );
105+ if (!find_pack_entry_one (& oid , dest_pack )) {
106+ string_list_clear (& line_sections , 0 );
107+ continue ;
108+ }
109+
110+ /* If <time> doesn't exist, retrieve it and add it to line */
111+ if (line_sections .nr < 3 )
112+ strbuf_addf (& line , " %" PRItime ,
113+ (timestamp_t )source_stat .st_mtime );
114+
115+ /*
116+ * Add the finalized line to dest_to_write and dest_content if it
117+ * wasn't already present inside dest_content
118+ */
119+ if (strset_add (& dest_content , line .buf )) {
120+ strbuf_addbuf (& dest_to_write , & line );
121+ strbuf_addch (& dest_to_write , '\n' );
122+ }
123+
124+ string_list_clear (& line_sections , 0 );
125+ }
126+
127+ err = ferror (source );
128+ err |= fclose (source );
129+ if (err )
130+ die (_ ("Could not read '%s' promisor file" ), source_promisor_name .buf );
131+ }
132+
133+ /* If dest_to_write is not empty, then there are new lines to append */
134+ if (dest_to_write .len ) {
135+ if (fseek (dest , 0L , SEEK_END ))
136+ die_errno (_ ("fseek failed" ));
137+ fprintf (dest , "%s" , dest_to_write .buf );
138+ }
139+
140+ err = ferror (dest );
141+ err |= fclose (dest );
142+ if (err )
143+ die (_ ("Could not write '%s' promisor file" ), dest_promisor_name );
144+
145+ close_pack_index (dest_pack );
146+ free (dest_idx_name );
147+ free (dest_promisor_name );
148+ strset_clear (& dest_content );
149+ strbuf_release (& dest_to_write );
150+ strbuf_release (& source_promisor_name );
151+ strbuf_release (& line );
152+ }
153+
37154static void finish_repacking_promisor_objects (struct repository * repo ,
38155 struct child_process * cmd ,
39156 struct string_list * names ,
40- const char * packtmp )
157+ const char * packtmp ,
158+ struct strset * not_repacked_basenames )
41159{
42160 struct strbuf line = STRBUF_INIT ;
43161 FILE * out ;
@@ -55,19 +173,15 @@ static void finish_repacking_promisor_objects(struct repository *repo,
55173
56174 /*
57175 * pack-objects creates the .pack and .idx files, but not the
58- * .promisor file. Create the .promisor file, which is empty.
59- *
60- * NEEDSWORK: fetch-pack sometimes generates non-empty
61- * .promisor files containing the ref names and associated
62- * hashes at the point of generation of the corresponding
63- * packfile, but this would not preserve their contents. Maybe
64- * concatenate the contents of all .promisor files instead of
65- * just creating a new empty file.
176+ * .promisor file. Create the .promisor file.
66177 */
67178 promisor_name = mkpathdup ("%s-%s.promisor" , packtmp ,
68179 line .buf );
69180 write_promisor_file (promisor_name , NULL , 0 );
70181
182+ /* Now let's fill the content of the newly created .promisor file */
183+ copy_promisor_content (repo , line .buf , packtmp , not_repacked_basenames );
184+
71185 item -> util = generated_pack_populate (item -> string , packtmp );
72186
73187 free (promisor_name );
@@ -107,7 +221,7 @@ void repack_promisor_objects(struct repository *repo,
107221 return ;
108222 }
109223
110- finish_repacking_promisor_objects (repo , & cmd , names , packtmp );
224+ finish_repacking_promisor_objects (repo , & cmd , names , packtmp , NULL );
111225}
112226
113227void pack_geometry_repack_promisors (struct repository * repo ,
@@ -118,6 +232,7 @@ void pack_geometry_repack_promisors(struct repository *repo,
118232{
119233 struct child_process cmd = CHILD_PROCESS_INIT ;
120234 FILE * in ;
235+ struct strset not_repacked_basenames = STRSET_INIT ;
121236
122237 if (!geometry -> promisor_split )
123238 return ;
@@ -131,9 +246,15 @@ void pack_geometry_repack_promisors(struct repository *repo,
131246 in = xfdopen (cmd .in , "w" );
132247 for (size_t i = 0 ; i < geometry -> promisor_split ; i ++ )
133248 fprintf (in , "%s\n" , pack_basename (geometry -> promisor_pack [i ]));
134- for (size_t i = geometry -> promisor_split ; i < geometry -> promisor_pack_nr ; i ++ )
135- fprintf (in , "^%s\n" , pack_basename (geometry -> promisor_pack [i ]));
249+ for (size_t i = geometry -> promisor_split ; i < geometry -> promisor_pack_nr ; i ++ ) {
250+ const char * name = pack_basename (geometry -> promisor_pack [i ]);
251+ fprintf (in , "^%s\n" , name );
252+ strset_add (& not_repacked_basenames , name );
253+ }
136254 fclose (in );
137255
138- finish_repacking_promisor_objects (repo , & cmd , names , packtmp );
256+ finish_repacking_promisor_objects (repo , & cmd , names , packtmp ,
257+ strset_get_size (& not_repacked_basenames ) ? & not_repacked_basenames : NULL );
258+
259+ strset_clear (& not_repacked_basenames );
139260}
0 commit comments