forked from sched-ext/scx
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcargo-publish.py
More file actions
executable file
·127 lines (98 loc) · 3.8 KB
/
cargo-publish.py
File metadata and controls
executable file
·127 lines (98 loc) · 3.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#!/usr/bin/python
import argparse
import json
import re
import subprocess
import sys
publish_args={'scx_rlfifo': ['--no-verify'],
'scx_rustland': ['--no-verify']}
verbose = False
def err(line):
raise Exception(line)
def dbg(line):
if verbose:
print('[DBG] ' + line, file=sys.stderr)
def underline(string):
return f'\033[4m{string}\033[0m'
def get_crate_info():
metadata = subprocess.check_output(["cargo", "metadata", "--format-version", "1"])
metadata = json.loads(metadata)
default_members = set(metadata["workspace_default_members"])
crates = {}
for pkg in metadata["packages"]:
if pkg.get("publish") == []:
continue
if pkg["id"] in default_members:
deps = {dep["name"] for dep in pkg["dependencies"]
if dep["source"] is None and dep["kind"] != "dev"}
crates[pkg["name"]] = deps
return crates
def topological_sort(crates):
in_degree = {name: len(deps) for name, deps in crates.items()}
queue = [name for name, degree in in_degree.items() if degree == 0]
result = []
while queue:
queue.sort()
current = queue.pop(0)
result.append(current)
for name, deps in crates.items():
if current in deps:
in_degree[name] -= 1
if in_degree[name] == 0:
queue.append(name)
if len(result) != len(crates):
remaining = [name for name in crates if name not in result]
err(f'Circular dependency detected among crates: {remaining}')
return result
def publish(crate, extra_args, ignore_existing):
try:
proc = subprocess.run(['cargo', 'publish', '-p', crate] + extra_args,
check=True, capture_output=True)
except subprocess.CalledProcessError as e:
stdout = e.stdout.decode('utf-8').splitlines()
stderr = e.stderr.decode('utf-8').splitlines()
okay = False
if ignore_existing:
already_re = r'(^.*)(crate.*already uploaded)(.*$)'
m = re.match(already_re, stderr[-1])
if m:
print(f'IGNORE: {m.group(1)}{underline(m.group(2))}{m.group(3)}')
okay = True
if verbose or not okay:
for line in stdout:
print(f'STDOUT: {line}')
for line in stderr:
print(f'STDERR: {line}')
if not okay:
raise e
def main():
parser = argparse.ArgumentParser(prog='cargo-publish.py',
description='Publish rust projects, use --dry to see what it\'s going to do')
parser.add_argument('-s', '--start',
help='skip crates which come before this crate in the publishing order')
parser.add_argument('-i', '--ignore', action='store_true',
help='ignore errors from already published crates')
parser.add_argument('-d', '--dry', action='store_true')
parser.add_argument('-v', '--verbose', action='store_true')
args = parser.parse_args()
global verbose
verbose = args.verbose
crates = get_crate_info()
excess_publish_args = publish_args.keys() - crates.keys()
if excess_publish_args:
err(f'publish_args contains non-existent crates {excess_publish_args}')
if args.start and args.start not in crates:
err(f'--start specified non-existent crate {args.start}')
targets = topological_sort(crates)
# Publish
start_from = args.start
for target in targets:
if start_from and target != start_from:
continue
start_from = None
pargs = publish_args.get(target, [])
print(f'Publishing crate {target} {" ".join(pargs)}')
dbg(f'target: {target}')
if not args.dry:
publish(target, pargs, args.ignore)
main()