1 | /* |
2 | * Copyright 2016-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | /** |
18 | * `Shell` provides a collection of functions to use with `Subprocess` that make |
19 | * it easier to safely run processes in a unix shell. |
20 | * |
21 | * Note: use this rarely and carefully. By default you should use `Subprocess` |
22 | * with a vector of arguments. |
23 | */ |
24 | |
25 | #pragma once |
26 | |
27 | #include <string> |
28 | #include <vector> |
29 | |
30 | #include <folly/Conv.h> |
31 | #include <folly/Format.h> |
32 | #include <folly/Range.h> |
33 | |
34 | namespace folly { |
35 | |
36 | /** |
37 | * Quotes an argument to make it suitable for use as shell command arguments. |
38 | */ |
39 | std::string shellQuote(StringPiece argument); |
40 | |
41 | namespace detail { |
42 | template <typename... Arguments> |
43 | std::vector<std::string> shellify( |
44 | StringPiece format, |
45 | Arguments&&... arguments) { |
46 | auto command = sformat( |
47 | format, |
48 | shellQuote(to<std::string>(std::forward<Arguments>(arguments)))...); |
49 | return {"/bin/sh" , "-c" , command}; |
50 | } |
51 | |
52 | struct ShellCmdFormat { |
53 | StringPiece format; |
54 | template <typename... Arguments> |
55 | std::vector<std::string> operator()(Arguments&&... arguments) const { |
56 | return ::folly::detail::shellify( |
57 | format, std::forward<Arguments>(arguments)...); |
58 | } |
59 | }; |
60 | |
61 | } // namespace detail |
62 | |
63 | inline namespace literals { |
64 | inline namespace shell_literals { |
65 | constexpr detail::ShellCmdFormat operator"" _shellify( |
66 | char const* name, |
67 | std::size_t length) { |
68 | return {folly::StringPiece(name, length)}; |
69 | } |
70 | } // namespace shell_literals |
71 | } // namespace literals |
72 | |
73 | /** |
74 | * Create argument array for `Subprocess()` for a process running in a |
75 | * shell. |
76 | * |
77 | * The shell to use is always going to be `/bin/sh`. |
78 | * |
79 | * This is deprecated in favour of the user-defined-literal `_shellify` |
80 | * from namespace `folly::shell_literals` because that requires that the format |
81 | * string is a compile-time constant which can be inspected during code reviews |
82 | */ |
83 | // clang-format off |
84 | template <typename... Arguments> |
85 | [[deprecated( |
86 | "Use `\"command {} {} ...\"_shellify(argument1, argument2 ...)` from " |
87 | "namespace `folly::literals::shell_literals`" )]] |
88 | std::vector<std::string> shellify( |
89 | StringPiece format, |
90 | Arguments&&... arguments) { |
91 | return detail::shellify(format, std::forward<Arguments>(arguments)...); |
92 | } |
93 | // clang-format on |
94 | |
95 | } // namespace folly |
96 | |