Skip to content

Commit 3ad27d7

Browse files
committed
Merge branch 'main' into DOC-5042
2 parents 149e1ac + c04c829 commit 3ad27d7

File tree

111 files changed

+37669
-299
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

111 files changed

+37669
-299
lines changed

build/image_report.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
"""Image report
2+
"""
3+
4+
from pylibs.hugotools import ShortcodeIterator
5+
6+
import argparse
7+
import os
8+
9+
10+
def scan_file(path: str) -> int:
11+
"""Scans a file for all `image` shortcodes.
12+
13+
Args:
14+
path (str): Path to file.
15+
16+
Returns:
17+
(int) Number of shortcodes found.
18+
"""
19+
20+
img_list = []
21+
22+
with open(path, encoding="utf_8") as md_file:
23+
text = md_file.read()
24+
25+
for img, pos_info in ShortcodeIterator(
26+
text, lambda t: t.tag == "image"
27+
):
28+
img_list.append((img, pos_info))
29+
30+
if len(img_list) > 0:
31+
print(f"File '{path}':")
32+
33+
for img in img_list:
34+
print(
35+
f" Line {img[1].line}: '{img[0].named_params['filename']}'"
36+
)
37+
38+
return len(img_list)
39+
40+
41+
parser = argparse.ArgumentParser(
42+
"Image report",
43+
"Scans a folder and report all Hugo image shortcodes found"
44+
)
45+
46+
parser.add_argument("pathname", help="Path of the folder to scan")
47+
48+
args = parser.parse_args()
49+
50+
print(f"Scanning '{args.pathname}'")
51+
52+
num_found = 0
53+
54+
for root, dirs, files in os.walk(args.pathname):
55+
for file in files:
56+
if file.endswith(".md"):
57+
fullpath = os.path.join(root, file)
58+
num_found += scan_file(fullpath)
59+
60+
if num_found == 0:
61+
print(f"No image shortcodes found in '{args.pathname}'")
62+
else:
63+
print(f"Found {num_found} image shortcodes.")

build/pylibs/hugotools.py

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
from enum import Enum
2+
from typing import Iterator, Match, Callable
3+
4+
import re
5+
6+
7+
class TextPosInfo:
8+
line: int
9+
start: int
10+
end: int
11+
12+
def __init__(self, line, start, end):
13+
self.line = line
14+
self.start = start
15+
self.end = end
16+
17+
18+
shortcode_re_pattern_start = r"(\n)|\{\{[<%]\s*"
19+
shortcode_re_body = r"(/)?([\w\-]+)\s*(.+?)?"
20+
shortcode_re_pattern_end = r"\s*[>%]\}\}"
21+
22+
shortcode_re_pattern = (
23+
shortcode_re_pattern_start +
24+
shortcode_re_body +
25+
shortcode_re_pattern_end
26+
)
27+
28+
29+
class ShortcodeTagType(Enum):
30+
"""Specifies open or close shortcode tag."""
31+
OPEN = 1
32+
CLOSE = 2
33+
34+
35+
class ShortcodeInfo:
36+
"""Represents the information in a shortcode.
37+
"""
38+
tag_type: ShortcodeTagType
39+
tag: str
40+
pos_params: list[str]
41+
named_params: dict[str, str]
42+
43+
def parse_params(self, param_str: str):
44+
param_re = "|".join([
45+
r'"(([^"]|(?<=\\)")*)"',
46+
r'((\w+)=([^"\s]+))',
47+
r'((\w+)="(([^"]|(?<=\\)")*)")',
48+
r'([^"=\s]+)'
49+
])
50+
51+
for match in re.finditer(param_re, param_str):
52+
if match is None:
53+
self.pos_params = []
54+
self.named_params = {}
55+
return
56+
57+
if match[1]:
58+
self.pos_params.append(re.sub(r'\\"', '"', match[1]))
59+
elif match[3]:
60+
self.named_params[match[4]] = match[5]
61+
elif match[6]:
62+
self.named_params[match[7]] = re.sub(r'\\"', '"', match[8])
63+
elif match[10]:
64+
self.pos_params.append(match[10])
65+
66+
def __init__(
67+
self, tag: str,
68+
tag_type: ShortcodeTagType,
69+
param_text: str = ""
70+
):
71+
self.tag = tag
72+
self.tag_type = tag_type
73+
self.pos_params = []
74+
self.named_params = {}
75+
self.parse_params(param_text or "")
76+
77+
def __str__(self) -> str:
78+
type_text: str
79+
80+
if self.tag_type == ShortcodeTagType.OPEN:
81+
type_text = "OPEN"
82+
else:
83+
type_text = "CLOSE"
84+
85+
result = f"{type_text} {self.tag}"
86+
87+
if self.pos_params or self.named_params:
88+
result += ":"
89+
90+
for pos_param in self.pos_params:
91+
result += f"\n '{pos_param}'"
92+
93+
for named_param, named_value in self.named_params.items():
94+
result += f"\n {named_param} = {named_value}"
95+
96+
return result
97+
98+
99+
class ShortcodeIterator:
100+
"""Iterates through all shortcodes in a string.
101+
"""
102+
re_iterator: Iterator[Match[str]]
103+
linenum: int
104+
sc_filter: Callable[[ShortcodeInfo], bool]
105+
106+
def __init__(
107+
self,
108+
text: str,
109+
sc_filter: Callable[[ShortcodeInfo], bool] = lambda x: True
110+
):
111+
self.re_iterator = re.finditer(shortcode_re_pattern, text)
112+
self.sc_filter = lambda self, x: sc_filter(x)
113+
self.linenum = 1
114+
115+
def __iter__(self):
116+
return self
117+
118+
def __next__(self) -> tuple[ShortcodeInfo, TextPosInfo]:
119+
next_match = self.re_iterator.__next__()
120+
121+
while True:
122+
if next_match[1]:
123+
self.linenum += 1
124+
elif next_match[2]:
125+
result = ShortcodeInfo(
126+
next_match[3], ShortcodeTagType.CLOSE
127+
)
128+
129+
if self.sc_filter(self, result):
130+
return (
131+
result,
132+
TextPosInfo(
133+
self.linenum,
134+
next_match.start(),
135+
next_match.end()
136+
)
137+
)
138+
else:
139+
result = ShortcodeInfo(
140+
next_match[3],
141+
ShortcodeTagType.OPEN,
142+
next_match[4]
143+
)
144+
145+
if self.sc_filter(self, result):
146+
return (
147+
result,
148+
TextPosInfo(
149+
self.linenum,
150+
next_match.start(),
151+
next_match.end()
152+
)
153+
)
154+
155+
next_match = self.re_iterator.__next__()

content/develop/clients/go/queryjson.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ Specify query options to return only the `city` field:
102102
{{< clients-example go_home_json query2 >}}
103103
{{< /clients-example >}}
104104

105+
You can also use the same query with the `CountOnly` option
106+
enabled to get the number of documents found without
107+
returning the documents themselves.
108+
109+
{{< clients-example go_home_json query2count_only >}}
110+
{{< /clients-example >}}
111+
105112
Use an
106113
[aggregation query]({{< relref "/develop/interact/search-and-query/query/aggregation" >}})
107114
to count all users in each city.

content/develop/clients/nodejs/connect.md

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ createClient({
6767
```
6868
To check if the client is connected and ready to send commands, use `client.isReady`, which returns a Boolean. `client.isOpen` is also available. This returns `true` when the client's underlying socket is open, and `false` when it isn't (for example, when the client is still connecting or reconnecting after a network error).
6969

70-
### Connect to a Redis cluster
70+
## Connect to a Redis cluster
7171

7272
To connect to a Redis cluster, use `createCluster`.
7373

@@ -97,7 +97,7 @@ console.log(value); // returns 'bar'
9797
await cluster.quit();
9898
```
9999

100-
### Connect to your production Redis with TLS
100+
## Connect to your production Redis with TLS
101101

102102
When you deploy your application, use TLS and follow the [Redis security]({{< relref "/operate/oss_and_stack/management/security/" >}}) guidelines.
103103

@@ -127,3 +127,77 @@ await client.disconnect();
127127
```
128128

129129
You can also use discrete parameters and UNIX sockets. Details can be found in the [client configuration guide](https://github.com/redis/node-redis/blob/master/docs/client-configuration.md).
130+
131+
## Reconnect after disconnection
132+
133+
By default, `node-redis` doesn't attempt to reconnect automatically when
134+
the connection to the server is lost. However, you can set the
135+
`socket.reconnectionStrategy` field in the configuration to decide
136+
whether to try to reconnect and how to approach it. Choose one of the following values for
137+
`socket.reconnectionStrategy`:
138+
139+
- `false`: (Default) Don't attempt to reconnect.
140+
- `number`: Wait for this number of milliseconds and then attempt to reconnect.
141+
- `<function>`: Use a custom
142+
function to decide how to handle reconnection.
143+
144+
The custom function has the following signature:
145+
146+
```js
147+
(retries: number, cause: Error) => false | number | Error
148+
```
149+
150+
It is called before each attempt to reconnect, with the `retries`
151+
indicating how many attempts have been made so far. The `cause` parameter is an
152+
[`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
153+
object with information about how the connection was lost. The return value
154+
from the function can be any of the following:
155+
156+
- `false`: Don't attempt to reconnect.
157+
- `number`: Wait this number of milliseconds and then try again.
158+
- `Error`: Same as `false`, but lets you supply extra information about why
159+
no attempt was made to reconnect.
160+
161+
The example below shows a `reconnectionStrategy` function that implements a
162+
custom [exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff)
163+
strategy:
164+
165+
```js
166+
createClient({
167+
socket: {
168+
reconnectStrategy: retries => {
169+
// Generate a random jitter between 0 – 200 ms:
170+
const jitter = Math.floor(Math.random() * 200);
171+
172+
// Delay is an exponential back off, (times^2) * 50 ms, with a
173+
// maximum value of 2000 ms:
174+
const delay = Math.min(Math.pow(2, retries) * 50, 2000);
175+
176+
return delay + jitter;
177+
}
178+
}
179+
});
180+
```
181+
182+
## Connection events
183+
184+
The client object emits the following
185+
[events](https://developer.mozilla.org/en-US/docs/Web/API/Event) that are
186+
related to connection:
187+
188+
- `connect`: (No parameters) The client is about to start connecting to the server.
189+
- `ready`: (No parameters) The client has connected and is ready to use.
190+
- `end`: (No parameters) The client has been intentionally closed using `client.quit()`.
191+
- `error`: An error has occurred, which is described by the
192+
[`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
193+
parameter. This is usually a network issue such as "Socket closed unexpectedly".
194+
- `reconnecting`: (No parameters) The client is about to try reconnecting after the
195+
connection was lost due to an error.
196+
197+
Use code like the following to respond to these events:
198+
199+
```js
200+
client.on('error', error => {
201+
console.error(`Redis client error:`, error);
202+
});
203+
```

0 commit comments

Comments
 (0)