-
Notifications
You must be signed in to change notification settings - Fork 2
/
rccli.py
executable file
·254 lines (204 loc) · 9.01 KB
/
rccli.py
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
#!/usr/bin/env python
"""
Command line interface to access the Rosetta Code site.
Pretty rudimentary; just thrown together to make it
possible to invoke by anyone that doesn't want to use
the API directly.
Some example uses:
./rccli.py --task '100_doors'
- list the languages in '100_doors'
./rccli.py --task '100_doors' --languages --count
- list the languagse with counts of the code blocks
./rccli.py --task '100_doors' --code
- list all the code in all the languages
./rccli.py --task '100_doors' --language 'C' --code
- show the code blocks for C code in '100_doors'
./rccli.py --category 'C' --tasks
- list all the tasks in the 'C' category
./rccli.py --catgeory 'C' --json
- Dump JSON for the data in the 'C' category.
./rccli.py --category 'C' --json --file 'my.json'
- Dump JSON for the data in the 'C' category to a file.
./rccli.py --task '100_doors' --dir 'code'
- Extract all the code from the '100_doors' task in to a directory
./rccli.py --task '100_doors' --language 'C' --dir 'code'
- Extract the C code from the '100_doors' task in to a directory
./rccli.py --category 'C' --language 'C' --dir 'code'
- Extract the C code all tasks in the 'C' category in to a directory
"""
import argparse
import os
import sys
# Local libraries
from rosettacode import Task, Category
import json_funcs
def list_task(task, options, fh=None, base_indent=''):
if fh is None:
fh = sys.stdout
for lang in sorted(task.values()):
indent = base_indent
if options.languages:
if options.count:
fh.write("%s%s (%s)\n" % (indent, lang.name, len(lang.blocks)))
else:
fh.write("%s%s\n" % (indent, lang.name))
indent += ' '
if options.code:
for index, block in enumerate(lang.blocks):
fh.write("%s#%s:\n" % (indent, index))
for line in block.code.splitlines():
fh.write("%s %s\n" % (indent, line))
def comment(language, block):
"""
Return a block of a comment for a given language.
If we don't know the language, we'll use # prefix.
"""
if language in ('C', 'C++'):
return "/*%s\n*/\n" % (block,)
if language == 'BBC BASIC':
prefix = 'REM '
else:
prefix = "# "
lines = [prefix + line + "\n" for line in block.splitlines()]
return "".join(lines)
def write_tasks_dir(tasks, code_dir='code',
layout='unix',
include_task=False,
include_intro=False):
"""
Write out all the tasks in the list to a set of directories.
Using the 'riscos' layout will write out as <dir>/<extension>/<name>.
Using the 'unix' layout will write out as <dir>/<name>.<extension>.
"""
for task in tasks:
for lang in task.values():
# This won't be right for many files, but let's be consistent
extension = lang.name.lower().replace('/', '.').replace(' ', '_').encode('utf-8')
for index, code in enumerate(lang.blocks):
variant = index + 1
if len(lang.blocks) > 1:
name = "%s__%s" % (task.fsname, variant)
else:
name = task.fsname
if layout == 'riscos':
filename = os.path.join(code_dir, extension, name)
else:
leafname = '%s.%s' % (name, extension)
filename = os.path.join(code_dir, leafname)
dirname = os.path.dirname(filename)
if not os.path.isdir(dirname):
os.makedirs(dirname)
# Report the progress...
print("File: %s" % (filename,))
with open(filename, 'w') as fh:
if include_intro and task.intro:
fh.write(comment(lang.name, "\n" + task.intro.encode('utf-8', 'replace')) + "\n")
if include_task and task.task:
fh.write(comment(lang.name, " TASK:\n" + task.task.encode('utf-8', 'replace')) + "\n")
fh.write(code.code.encode('utf-8'))
# Ensure we always end on a newline
fh.write("\n")
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--task', type=str, default=None,
help="Name of a Task to process")
parser.add_argument('--category', type=str, default=None,
help="Name of a Category of process")
parser.add_argument('--language', type=str, default=None,
help="Language to list")
parser.add_argument('--tasks', action='store_true', default=False,
help='Report the tasks')
parser.add_argument('--languages', action='store_true', default=False,
help='Report the languages')
parser.add_argument('--count', action='store_true', default=False,
help='Report a count of the sub-resources')
parser.add_argument('--code', action='store_true', default=False,
help='Report the code')
parser.add_argument('--list', action='store_true', default=False,
help="Report the results as a list")
parser.add_argument('--json', action='store_true', default=False,
help="Report the elements as JSON")
parser.add_argument('--dir', type=str, default=None,
help="Report results to a directory structure")
parser.add_argument('--layout', choices=('unix', 'riscos'), default='unix',
help="Layout of the directory structure ('unix' or 'riscos')")
parser.add_argument('--file', type=str, default=None,
help="Report results to a file (for list, and json)")
options = parser.parse_args()
result = None
if options.category:
# This will be UTF-8 encoded, so we need to decode to the unicode we use
# internally.
options.category = options.category.decode('utf-8')
result = Category(options.category)
elif options.task:
# What they supplied will be UTF-8 encoded; so let's decode it to get
# the unicode name that we expect internall.
options.task = options.task.decode('utf-8')
result = Task(options.task)
if result is None:
print("No query requested; use --task or --category to select tasks")
if options.language:
if isinstance(result, Task):
result.language_filter = lambda lang: lang.name == options.language
if isinstance(result, Category):
# They want all the tasks in the category, which have a given language
def task_filter(task):
task.language_filter = lambda lang: lang.name == options.language
if task.get(options.language, None):
return True
return False
result.task_filter = task_filter
# If they don't specify an output default to list
if not options.list and not options.dir and not options.json:
options.list = True
if options.list:
# They just want a plain list of what's there.
if options.file:
fh = open(options.file, 'w')
else:
fh = sys.stdout
# If they didn't request anything, default to languages
if not options.tasks and not options.languages and not options.count and not options.code:
options.languages = True
if options.code:
options.languages = True
if isinstance(result, Task):
if options.count and not options.languages:
fh.write("%s\n" % (len(result.keys()),))
else:
list_task(result, options, fh, base_indent='')
elif isinstance(result, Category):
if options.count and not options.languages and not options.tasks:
fh.write("%s\n" % (len(result.tasks),))
else:
tasks = result.tasks
for task in tasks:
if options.count and not options.tasks:
fh.write("%s (%s)\n" % (task.name, len(task.languages)))
else:
fh.write("%s\n" % (task.name,))
if options.languages:
list_task(task, options, base_indent=' ')
elif options.json:
# They want JSON output
if options.file:
fh = open(options.file, 'w')
else:
fh = sys.stdout
for chunk in json_funcs.json_iterable(result, pretty=True):
fh.write(chunk)
elif options.dir:
# They wanted a directory dump
code_dir = options.dir
tasks = []
if isinstance(result, Task):
tasks = [result]
elif isinstance(result, Category):
tasks = result.tasks
write_tasks_dir(tasks, code_dir,
layout=options.layout,
include_task=True,
include_intro=True)
if __name__ == "__main__":
main()