]>
Commit | Line | Data |
---|---|---|
e9e8adf1 MT |
1 | #include "builtin.h" |
2 | #include "config.h" | |
3 | #include "entry.h" | |
f394e093 | 4 | #include "gettext.h" |
e9e8adf1 MT |
5 | #include "parallel-checkout.h" |
6 | #include "parse-options.h" | |
7 | #include "pkt-line.h" | |
08c46a49 | 8 | #include "read-cache-ll.h" |
e9e8adf1 MT |
9 | |
10 | static void packet_to_pc_item(const char *buffer, int len, | |
11 | struct parallel_checkout_item *pc_item) | |
12 | { | |
13 | const struct pc_item_fixed_portion *fixed_portion; | |
14 | const char *variant; | |
15 | char *encoding; | |
16 | ||
17 | if (len < sizeof(struct pc_item_fixed_portion)) | |
18 | BUG("checkout worker received too short item (got %dB, exp %dB)", | |
19 | len, (int)sizeof(struct pc_item_fixed_portion)); | |
20 | ||
21 | fixed_portion = (struct pc_item_fixed_portion *)buffer; | |
22 | ||
23 | if (len - sizeof(struct pc_item_fixed_portion) != | |
24 | fixed_portion->name_len + fixed_portion->working_tree_encoding_len) | |
25 | BUG("checkout worker received corrupted item"); | |
26 | ||
27 | variant = buffer + sizeof(struct pc_item_fixed_portion); | |
28 | ||
29 | /* | |
30 | * Note: the main process uses zero length to communicate that the | |
31 | * encoding is NULL. There is no use case that requires sending an | |
32 | * actual empty string, since convert_attrs() never sets | |
33 | * ca.working_tree_enconding to "". | |
34 | */ | |
35 | if (fixed_portion->working_tree_encoding_len) { | |
36 | encoding = xmemdupz(variant, | |
37 | fixed_portion->working_tree_encoding_len); | |
38 | variant += fixed_portion->working_tree_encoding_len; | |
39 | } else { | |
40 | encoding = NULL; | |
41 | } | |
42 | ||
43 | memset(pc_item, 0, sizeof(*pc_item)); | |
96168827 | 44 | pc_item->ce = make_empty_transient_cache_entry(fixed_portion->name_len, NULL); |
e9e8adf1 MT |
45 | pc_item->ce->ce_namelen = fixed_portion->name_len; |
46 | pc_item->ce->ce_mode = fixed_portion->ce_mode; | |
47 | memcpy(pc_item->ce->name, variant, pc_item->ce->ce_namelen); | |
48 | oidcpy(&pc_item->ce->oid, &fixed_portion->oid); | |
49 | ||
50 | pc_item->id = fixed_portion->id; | |
51 | pc_item->ca.crlf_action = fixed_portion->crlf_action; | |
52 | pc_item->ca.ident = fixed_portion->ident; | |
53 | pc_item->ca.working_tree_encoding = encoding; | |
54 | } | |
55 | ||
56 | static void report_result(struct parallel_checkout_item *pc_item) | |
57 | { | |
4dbc55e8 | 58 | struct pc_item_result res = { 0 }; |
e9e8adf1 MT |
59 | size_t size; |
60 | ||
61 | res.id = pc_item->id; | |
62 | res.status = pc_item->status; | |
63 | ||
64 | if (pc_item->status == PC_ITEM_WRITTEN) { | |
65 | res.st = pc_item->st; | |
66 | size = sizeof(res); | |
67 | } else { | |
68 | size = PC_ITEM_RESULT_BASE_SIZE; | |
69 | } | |
70 | ||
71 | packet_write(1, (const char *)&res, size); | |
72 | } | |
73 | ||
74 | /* Free the worker-side malloced data, but not pc_item itself. */ | |
75 | static void release_pc_item_data(struct parallel_checkout_item *pc_item) | |
76 | { | |
77 | free((char *)pc_item->ca.working_tree_encoding); | |
78 | discard_cache_entry(pc_item->ce); | |
79 | } | |
80 | ||
81 | static void worker_loop(struct checkout *state) | |
82 | { | |
83 | struct parallel_checkout_item *items = NULL; | |
84 | size_t i, nr = 0, alloc = 0; | |
85 | ||
86 | while (1) { | |
ec9a37d6 ÆAB |
87 | int len = packet_read(0, packet_buffer, sizeof(packet_buffer), |
88 | 0); | |
e9e8adf1 MT |
89 | |
90 | if (len < 0) | |
91 | BUG("packet_read() returned negative value"); | |
92 | else if (!len) | |
93 | break; | |
94 | ||
95 | ALLOC_GROW(items, nr + 1, alloc); | |
96 | packet_to_pc_item(packet_buffer, len, &items[nr++]); | |
97 | } | |
98 | ||
99 | for (i = 0; i < nr; i++) { | |
100 | struct parallel_checkout_item *pc_item = &items[i]; | |
101 | write_pc_item(pc_item, state); | |
102 | report_result(pc_item); | |
103 | release_pc_item_data(pc_item); | |
104 | } | |
105 | ||
106 | packet_flush(1); | |
107 | ||
108 | free(items); | |
109 | } | |
110 | ||
111 | static const char * const checkout_worker_usage[] = { | |
112 | N_("git checkout--worker [<options>]"), | |
113 | NULL | |
114 | }; | |
115 | ||
116 | int cmd_checkout__worker(int argc, const char **argv, const char *prefix) | |
117 | { | |
118 | struct checkout state = CHECKOUT_INIT; | |
119 | struct option checkout_worker_options[] = { | |
120 | OPT_STRING(0, "prefix", &state.base_dir, N_("string"), | |
121 | N_("when creating files, prepend <string>")), | |
122 | OPT_END() | |
123 | }; | |
124 | ||
125 | if (argc == 2 && !strcmp(argv[1], "-h")) | |
126 | usage_with_options(checkout_worker_usage, | |
127 | checkout_worker_options); | |
128 | ||
129 | git_config(git_default_config, NULL); | |
130 | argc = parse_options(argc, argv, prefix, checkout_worker_options, | |
131 | checkout_worker_usage, 0); | |
132 | if (argc > 0) | |
133 | usage_with_options(checkout_worker_usage, checkout_worker_options); | |
134 | ||
135 | if (state.base_dir) | |
136 | state.base_dir_len = strlen(state.base_dir); | |
137 | ||
138 | /* | |
139 | * Setting this on a worker won't actually update the index. We just | |
140 | * need to tell the checkout machinery to lstat() the written entries, | |
141 | * so that we can send this data back to the main process. | |
142 | */ | |
143 | state.refresh_cache = 1; | |
144 | ||
145 | worker_loop(&state); | |
146 | return 0; | |
147 | } |