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