Skip to content
This repository was archived by the owner on Aug 29, 2023. It is now read-only.

Commit 652845c

Browse files
Merge pull request #13 from provenance-io/log-tailing
Unit testing
2 parents 87d023e + f595276 commit 652845c

File tree

11 files changed

+647
-55
lines changed

11 files changed

+647
-55
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ build
44
dist
55
venv
66
.DS_Store
7+
.coverage
8+
htmlcov

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@ forge interactive
2525

2626
* The repo would then checkout to the release version and the binaries would be built, genesis file downloaded/constructed, and a command to run the node would be output to the console.
2727

28+
### Optional
29+
30+
Forge uses the GitHub Api to pull information about the provenance repo for you to use when spinning up a node. If you use forge a lot in a short time, you could hit the 60 calls per hour limit. You can add a GitHub Api Token to your environment in order to increase this to 5000 calls per hour.
31+
32+
You can follow the instructions [Here](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) to setup a personal access token.
33+
Once that is complete, add the token generated to your environment:
34+
```sh
35+
GITHUB_API_TOKEN=token_value
36+
```
2837

2938
### Forge comes with command line tools that can speed up the process.
3039

forgepb/builder.py

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def build(environment, network, config, provenance_branch=None, version=None, ar
2222
elif not provenance_branch and version:
2323
if version and version not in utils.get_versions():
2424
print(
25-
"The version entered doesn't exist in provenance. Please run 'forge -lsv' to list all versions")
25+
"The version entered doesn't exist in provenance. Please run 'forge provenance tags' to list all versions")
2626
return
2727
repo = git.Repo(provenance_path)
2828
repo.git.reset('--hard')
@@ -88,7 +88,7 @@ def build(environment, network, config, provenance_branch=None, version=None, ar
8888
utils.persist_localnet_information(
8989
build_path, config, version, validator_info)
9090

91-
run_command = "{}/bin/provenanced start --home {}".format(
91+
run_command = "{}/bin/provenanced start --home {} -t".format(
9292
build_path, build_path).split(" ")
9393
log_path = '{}/logs/{}.txt'.format(build_path,
9494
str(datetime.datetime.now()).replace(' ', '-'))
@@ -170,27 +170,27 @@ def build(environment, network, config, provenance_branch=None, version=None, ar
170170

171171

172172
def populate_genesis(build_path, moniker, chain_id):
173-
command1 = "{}/bin/provenanced --home {} init {} --chain-id {};".format(
173+
command1 = "{}/bin/provenanced --home {} -t init {} --chain-id {};".format(
174174
build_path, build_path, moniker, chain_id)
175-
command2 = "{}/bin/provenanced --home {} keys add validator --keyring-backend test 2>&1;".format(
175+
command2 = "{}/bin/provenanced --home {} -t keys add validator --keyring-backend test 2>&1;".format(
176176
build_path, build_path, build_path)
177-
command3 = "{}/bin/provenanced --home {} add-genesis-root-name validator pio --keyring-backend test 2>&- || echo pio root name already exists, skipping...;".format(
177+
command3 = "{}/bin/provenanced --home {} -t add-genesis-root-name validator pio --keyring-backend test 2>&- || echo pio root name already exists, skipping...;".format(
178178
build_path, build_path)
179-
command3 += "{}/bin/provenanced --home {} add-genesis-root-name validator pb --restrict=false --keyring-backend test 2>&- || echo pb root name already exists, skipping...;".format(
179+
command3 += "{}/bin/provenanced --home {} -t add-genesis-root-name validator pb --restrict=false --keyring-backend test 2>&- || echo pb root name already exists, skipping...;".format(
180180
build_path, build_path)
181-
command3 += "{}/bin/provenanced --home {} add-genesis-root-name validator io --restrict --keyring-backend test 2>&- || echo io root name already exists, skipping...;".format(
181+
command3 += "{}/bin/provenanced --home {} -t add-genesis-root-name validator io --restrict --keyring-backend test 2>&- || echo io root name already exists, skipping...;".format(
182182
build_path, build_path)
183-
command3 += "{}/bin/provenanced --home {} add-genesis-root-name validator provenance --keyring-backend test 2>&- || echo validator root name already exists, skipping...;".format(
183+
command3 += "{}/bin/provenanced --home {} -t add-genesis-root-name validator provenance --keyring-backend test 2>&- || echo validator root name already exists, skipping...;".format(
184184
build_path, build_path)
185-
command3 += "{}/bin/provenanced --home {} add-genesis-account validator 100000000000000000000nhash --keyring-backend test 2>&-;".format(
185+
command3 += "{}/bin/provenanced --home {} -t add-genesis-account validator 100000000000000000000nhash --keyring-backend test 2>&-;".format(
186186
build_path, build_path)
187-
command3 += "{}/bin/provenanced --home {} gentx validator 1000000000000000nhash --keyring-backend test --chain-id={} 2>&- || echo gentx file already exists, skipping;".format(
187+
command3 += "{}/bin/provenanced --home {} -t gentx validator 1000000000000000nhash --keyring-backend test --chain-id={} 2>&- || echo gentx file already exists, skipping;".format(
188188
build_path, build_path, chain_id)
189-
command3 += "{}/bin/provenanced --home {} add-genesis-marker 100000000000000000000nhash --manager validator --access mint,burn,admin,withdraw,deposit --activate --keyring-backend test 2>&- || echo existing address, skipping;".format(
189+
command3 += "{}/bin/provenanced --home {} -t add-genesis-marker 100000000000000000000nhash --manager validator --access mint,burn,admin,withdraw,deposit --activate --keyring-backend test 2>&- || echo existing address, skipping;".format(
190190
build_path, build_path)
191-
command3 += "{}/bin/provenanced --home {} collect-gentxs".format(
191+
command3 += "{}/bin/provenanced --home {} -t collect-gentxs".format(
192192
build_path, build_path)
193-
validator_check_command = "{}/bin/provenanced --home {} keys show validator".format(
193+
validator_check_command = "{}/bin/provenanced --home {} -t keys show validator".format(
194194
build_path, build_path)
195195
os.system(command1)
196196
validator_check_process = subprocess.Popen(
@@ -231,25 +231,25 @@ def spawnDaemon(node_command, version, network, config, log_path):
231231

232232
def start_node(node_command, version, network, config, log_path):
233233
try:
234-
log = open(log_path, 'w+')
235-
print('Running {}'.format(' '.join(node_command)))
236-
print('You can view the logs here: {}'.format(log_path))
237-
process = subprocess.Popen(
238-
node_command, shell=False, stdout=log, stderr=log)
239-
if network == 'localnet':
240-
config[network][version]['run-command'] = node_command
241-
config[network][version]['log-path'] = log_path
242-
else:
243-
config[network]['run-command'] = node_command
244-
config[network]['log-path'] = log_path
245-
config['running-node'] = True
246-
config['running-node-info'] = {
247-
"pid": process.pid,
248-
"version": version,
249-
"network": network
250-
}
251-
utils.save_config(config)
252-
process.wait()
234+
with open(log_path, 'w+') as log:
235+
print('Running {}'.format(' '.join(node_command)))
236+
print('You can view the logs here: {}'.format(log_path))
237+
process = subprocess.Popen(
238+
node_command, shell=False, stdout=log, stderr=log)
239+
if network == 'localnet':
240+
config[network][version]['run-command'] = node_command
241+
config[network][version]['log-path'] = log_path
242+
else:
243+
config[network]['run-command'] = node_command
244+
config[network]['log-path'] = log_path
245+
config['running-node'] = True
246+
config['running-node-info'] = {
247+
"pid": process.pid,
248+
"version": version,
249+
"network": network
250+
}
251+
utils.save_config(config)
252+
process.wait()
253253
except FileNotFoundError:
254254
print("It looks like a node was initialized and deleted.\nForge is removing this from the config so you can run the same command again and the node will be initialized and started.".format())
255255
config.pop(network)

forgepb/cmd/node.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,8 @@ def node_init_cmd(network, tag, moniker, chain_id, provenance_branch, boot_args)
195195
os.path.expanduser('~'))['config']
196196
provenance_path = config['saveDir'] + "forge" + "/provenance"
197197
print("Cloning repo, this can take a few seconds...")
198-
git.Repo.clone_from(global_.PROVENANCE_REPO, provenance_path)
198+
if not os.path.exists(provenance_path):
199+
git.Repo.clone_from(global_.PROVENANCE_REPO, provenance_path)
199200
if not tag and not provenance_branch and not network:
200201
provenance_branch = 'main'
201202
if not moniker:
@@ -228,8 +229,7 @@ def node_status_cmd():
228229
print(json.dumps(node_status, indent=4))
229230
else:
230231
print(message)
231-
exit()
232-
232+
return
233233

234234
@click.command(
235235
'mnemonic',
@@ -259,15 +259,15 @@ def node_list_mnemonic_cmd(tag, provenance_branch):
259259
if tag:
260260
if tag not in utils.get_versions():
261261
print(
262-
"The version entered doesn't exist in provenance. Please run 'forge -lsv' to list all versions")
262+
"The tag entered doesn't exist in provenance. Please run 'forge provenance tags' to list all tags")
263263
else:
264264
print(" ".join(config['localnet'][tag]['mnemonic']))
265265
elif provenance_branch:
266266
if provenance_branch not in utils.get_remote_branches():
267267
print(
268-
"The version entered doesn't exist in provenance. Please run 'forge -lsv' to list all versions")
268+
"The branch entered doesn't exist in provenance. Please run 'forge provenance branches' to list all branches")
269269
else:
270-
print(" ".join([provenance_branch]['mnemonic']))
270+
print(" ".join(config['localnet'][provenance_branch]['mnemonic']))
271271
else:
272272
for version in config['localnet'].keys():
273273
print("Localnet version: {}\nMnemonic: {}".format(version, " ".join(config['localnet'][version]['mnemonic'])))

forgepb/utils.py

Lines changed: 79 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313

1414
# Pull existing config from file
1515
def load_config():
16-
config_file = open(global_.CONFIG_PATH + "/config.json")
17-
return json.load(config_file)
16+
with open(global_.CONFIG_PATH + "/config.json") as config_file:
17+
return json.load(config_file)
1818

1919

2020
def exists_config():
@@ -38,25 +38,29 @@ def get_version_info(network, environment, provenance_path):
3838

3939
if network == 'localnet':
4040
filtered_tags = get_versions()
41+
branches = get_remote_branches()
4142
for index, version_tag in zip(range(5), filtered_tags):
4243
print(version_tag)
4344
repo = git.Repo(provenance_path)
4445

4546
# In case of localnet, list release versions for user to select
4647
while version == None:
4748
try:
48-
version = input("Enter a release version from above. Run forge -v for full list of versions [{}]:\n".format(
49+
version = input("Enter a release version from above or a proveance branch. Run 'forge provenance tags' for full list of versions or 'forge provenance branches' for a full list of branches [{}]:\n".format(
4950
filtered_tags[0]))
5051
except ValueError:
5152
continue
5253
if not version:
5354
version = filtered_tags[0]
54-
if not version in filtered_tags:
55+
if not version in filtered_tags and not version in branches:
5556
version = None
5657

5758
# Checkout to branch for obtaining provenance binary
5859
# Version should be integer or sanitized
5960
try:
61+
repo.git.reset('--hard')
62+
repo.git.checkout('main')
63+
repo.remotes.origin.pull()
6064
repo.git.checkout("-f", "tags/{}".format(version), "-b", version)
6165
except git.exc.GitCommandError:
6266
repo.git.checkout("-f", version)
@@ -81,12 +85,12 @@ def select_network():
8185
except ValueError:
8286
continue
8387
if network == len(global_.NETWORK_STRINGS) + 1:
84-
exit()
88+
return
8589
if network > len(global_.NETWORK_STRINGS) or network < 1:
8690
continue
8791
builder.build(global_.CHAIN_ID_STRINGS[global_.NETWORK_STRINGS[network - 1]],
8892
global_.NETWORK_STRINGS[network - 1], config)
89-
exit()
93+
return
9094

9195

9296
# Collect moniker and chain id for a localnet node
@@ -216,6 +220,42 @@ def follow_logs(log_path):
216220
if p.poll(1):
217221
print(f.stdout.readline().decode('utf-8').strip())
218222

223+
# Print last 1000 lines from the log file given
224+
def print_logs(log_path):
225+
list_of_lines = []
226+
with open(log_path, 'rb') as read_obj:
227+
228+
read_obj.seek(0, os.SEEK_END)
229+
buffer = bytearray()
230+
pointer_location = read_obj.tell()
231+
while pointer_location >= 0 and len(list_of_lines) < 1000:
232+
read_obj.seek(pointer_location)
233+
pointer_location = pointer_location - 1
234+
new_byte = read_obj.read(1)
235+
if new_byte == b'\n':
236+
list_of_lines.append(buffer.decode('unicode_escape')[::-1])
237+
buffer = bytearray()
238+
else:
239+
buffer.extend(new_byte)
240+
if len(buffer) > 0:
241+
list_of_lines.append(buffer.decode()[::-1])
242+
for line in reversed(list_of_lines):
243+
print(line)
244+
time.sleep(.04)
245+
246+
247+
# Tail the logs
248+
def follow_logs(log_path):
249+
f = subprocess.Popen(['tail', '-F', log_path],
250+
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
251+
p = select.poll()
252+
p.register(f.stdout)
253+
254+
while True:
255+
if p.poll(1):
256+
print(f.stdout.readline().decode('utf-8').strip())
257+
258+
219259
# Fetch info stored for currently executing process.
220260
def view_running_node_info():
221261
if not exists_config():
@@ -284,7 +324,7 @@ def start_node():
284324
builder.spawnDaemon(
285325
node_info['run-command'], version, network, config, node_info['log-path'])
286326
except Exception:
287-
print("You haven't initialized a node. Try running 'forge' to start the wizard.")
327+
print("You haven't initialized a node. Try running 'forge i' to start the wizard.")
288328

289329

290330
def handle_running_node(process_information):
@@ -303,31 +343,53 @@ def handle_running_node(process_information):
303343

304344
# Returns a list of version tags for localnet to use
305345
def get_versions():
346+
github_api_token = os.getenv('GITHUB_API_TOKEN')
347+
if not github_api_token == None:
348+
headers = {'Authorization': 'token ' + github_api_token}
349+
else:
350+
headers = {}
306351
try:
307-
res=requests.get(global_.GITHUB_URL + 'tags?simple=yes&per_page=100&page=1')
308-
tag_info=res.json()
352+
res = requests.get(global_.GITHUB_URL +
353+
'tags?simple=yes&per_page=100&page=1', headers=headers)
354+
tag_info = res.json()
309355
while 'next' in res.links.keys():
310-
res=requests.get(res.links['next']['url'])
356+
res = requests.get(res.links['next']['url'])
311357
tag_info.extend(res.json())
312358
return [tag['name'] for tag in tag_info]
313359
except:
314-
print("Something went wrong reaching out to {}".format(
315-
global_.GITHUB_URL + 'branches'))
360+
if github_api_token == None:
361+
print("Something went wrong reaching out to {}\nTry adding GITHUB_API_TOKEN to your environment to increase number of times you can call the github api.".format(
362+
global_.GITHUB_URL + 'tags'))
363+
364+
else:
365+
print("Something went wrong reaching out to {}\nYou may be out of api requests which is limited to 5000 per hour".format(
366+
global_.GITHUB_URL + 'tags'))
316367
return False
317368

318369

319370
# Returns a list of all remote branches
320371
def get_remote_branches():
372+
github_api_token = os.getenv('GITHUB_API_TOKEN')
373+
if not github_api_token == None:
374+
headers = {'Authorization': 'token ' + github_api_token}
375+
else:
376+
headers = {}
321377
try:
322-
res=requests.get(global_.GITHUB_URL + 'branches?simple=yes&per_page=100&page=1')
323-
branch_info=res.json()
378+
res = requests.get(global_.GITHUB_URL +
379+
'branches?simple=yes&per_page=100&page=1', headers=headers)
380+
branch_info = res.json()
324381
while 'next' in res.links.keys():
325-
res=requests.get(res.links['next']['url'])
382+
res = requests.get(res.links['next']['url'])
326383
branch_info.extend(res.json())
327384
return [branch['name'] for branch in branch_info]
328385
except:
329-
print("Something went wrong reaching out to {}".format(
330-
global_.GITHUB_URL + 'branches'))
386+
if github_api_token == None:
387+
print("Something went wrong reaching out to {}\nTry adding GITHUB_API_TOKEN to your environment to increase number of times you can call the github api.".format(
388+
global_.GITHUB_URL + 'branches'))
389+
390+
else:
391+
print("Something went wrong reaching out to {}\nYou may be out of api requests which is limited to 5000 per hour".format(
392+
global_.GITHUB_URL + 'branches'))
331393
return False
332394

333395

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
]
2121
},
2222
keyword="provenance, node, bootstrap",
23+
description="Node manager for the Provenance Blockchain",
2324
long_description=long_description,
2425
long_description_content_type="text/markdown",
2526
)

tests/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)