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