##// END OF EJS Templates
Explicitly tell fileinput that we use '-' as read source...
marcink -
r3881:6b21a93d beta
parent child Browse files
Show More
@@ -1,168 +1,171 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.bin.gist
3 rhodecode.bin.gist
4 ~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~
5
5
6 Gist CLI client for RhodeCode
6 Gist CLI client for RhodeCode
7
7
8 :created_on: May 9, 2013
8 :created_on: May 9, 2013
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2013 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2013 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 from __future__ import with_statement
26 from __future__ import with_statement
27 import os
27 import os
28 import sys
28 import sys
29 import stat
29 import stat
30 import argparse
30 import argparse
31 import fileinput
31 import fileinput
32
32
33 from rhodecode.bin.base import json, api_call, RcConf, FORMAT_JSON, FORMAT_PRETTY
33 from rhodecode.bin.base import json, api_call, RcConf, FORMAT_JSON, FORMAT_PRETTY
34
34
35
35
36 def argparser(argv):
36 def argparser(argv):
37 usage = (
37 usage = (
38 "rhodecode-gist [-h] [--format=FORMAT] [--apikey=APIKEY] [--apihost=APIHOST] "
38 "rhodecode-gist [-h] [--format=FORMAT] [--apikey=APIKEY] [--apihost=APIHOST] "
39 "[--config=CONFIG] [--save-config] "
39 "[--config=CONFIG] [--save-config] [GIST OPTIONS] "
40 "[filename or stdin use - for terminal stdin ]\n"
40 "[filename or stdin use - for terminal stdin ]\n"
41 "Create config file: rhodecode-gist --apikey=<key> --apihost=http://rhodecode.server --save-config"
41 "Create config file: rhodecode-gist --apikey=<key> --apihost=http://rhodecode.server --save-config"
42 )
42 )
43
43
44 parser = argparse.ArgumentParser(description='RhodeCode Gist cli',
44 parser = argparse.ArgumentParser(description='RhodeCode Gist cli',
45 usage=usage)
45 usage=usage)
46
46
47 ## config
47 ## config
48 group = parser.add_argument_group('config')
48 group = parser.add_argument_group('config')
49 group.add_argument('--apikey', help='api access key')
49 group.add_argument('--apikey', help='api access key')
50 group.add_argument('--apihost', help='api host')
50 group.add_argument('--apihost', help='api host')
51 group.add_argument('--config', help='config file')
51 group.add_argument('--config', help='config file path DEFAULT: ~/.rhodecode')
52 group.add_argument('--save-config', action='store_true',
52 group.add_argument('--save-config', action='store_true',
53 help='save the given config into a file')
53 help='save the given config into a file')
54
54
55 group = parser.add_argument_group('GIST')
55 group = parser.add_argument_group('GIST')
56 group.add_argument('-f', '--filename', help='set uploaded gist filename')
57 group.add_argument('-p', '--private', action='store_true',
56 group.add_argument('-p', '--private', action='store_true',
58 help='Create private Gist')
57 help='create private Gist')
58 group.add_argument('-f', '--filename',
59 help='set uploaded gist filename, '
60 'also defines syntax highlighting')
59 group.add_argument('-d', '--description', help='Gist description')
61 group.add_argument('-d', '--description', help='Gist description')
60 group.add_argument('-l', '--lifetime', metavar='MINUTES',
62 group.add_argument('-l', '--lifetime', metavar='MINUTES',
61 help='Gist lifetime in minutes, -1 (Default) is forever')
63 help='gist lifetime in minutes, -1 (DEFAULT) is forever')
62 group.add_argument('--format', dest='format', type=str,
64 group.add_argument('--format', dest='format', type=str,
63 help='output format default: `%s` can '
65 help='output format DEFAULT: `%s` can '
64 'be also `%s`' % (FORMAT_PRETTY, FORMAT_JSON),
66 'be also `%s`' % (FORMAT_PRETTY, FORMAT_JSON),
65 default=FORMAT_PRETTY
67 default=FORMAT_PRETTY
66 )
68 )
67 args, other = parser.parse_known_args()
69 args, other = parser.parse_known_args()
68 return parser, args, other
70 return parser, args, other
69
71
70
72
71 def _run(argv):
73 def _run(argv):
72 conf = None
74 conf = None
73 parser, args, other = argparser(argv)
75 parser, args, other = argparser(argv)
74
76
75 api_credentials_given = (args.apikey and args.apihost)
77 api_credentials_given = (args.apikey and args.apihost)
76 if args.save_config:
78 if args.save_config:
77 if not api_credentials_given:
79 if not api_credentials_given:
78 raise parser.error('--save-config requires --apikey and --apihost')
80 raise parser.error('--save-config requires --apikey and --apihost')
79 conf = RcConf(config_location=args.config,
81 conf = RcConf(config_location=args.config,
80 autocreate=True, config={'apikey': args.apikey,
82 autocreate=True, config={'apikey': args.apikey,
81 'apihost': args.apihost})
83 'apihost': args.apihost})
82 sys.exit()
84 sys.exit()
83
85
84 if not conf:
86 if not conf:
85 conf = RcConf(config_location=args.config, autoload=True)
87 conf = RcConf(config_location=args.config, autoload=True)
86 if not conf:
88 if not conf:
87 if not api_credentials_given:
89 if not api_credentials_given:
88 parser.error('Could not find config file and missing '
90 parser.error('Could not find config file and missing '
89 '--apikey or --apihost in params')
91 '--apikey or --apihost in params')
90
92
91 apikey = args.apikey or conf['apikey']
93 apikey = args.apikey or conf['apikey']
92 host = args.apihost or conf['apihost']
94 host = args.apihost or conf['apihost']
93 DEFAULT_FILENAME = 'gistfile1.txt'
95 DEFAULT_FILENAME = 'gistfile1.txt'
94 if other:
96 if other:
95 # skip multifiles for now
97 # skip multifiles for now
96 filename = other[0]
98 filename = other[0]
97 if filename == '-':
99 if filename == '-':
98 filename = DEFAULT_FILENAME
100 filename = DEFAULT_FILENAME
99 gist_content = ''
101 gist_content = ''
100 for line in fileinput.input():
102 for line in fileinput.input('-'):
101 gist_content += line
103 gist_content += line
102 else:
104 else:
103 with open(filename, 'rb') as f:
105 with open(filename, 'rb') as f:
104 gist_content = f.read()
106 gist_content = f.read()
105
107
106 else:
108 else:
107 filename = DEFAULT_FILENAME
109 filename = DEFAULT_FILENAME
108 gist_content = None
110 gist_content = None
109 # little bit hacky but cross platform check where the
111 # little bit hacky but cross platform check where the
110 # stdin comes from we skip the terminal case it can be handled by '-'
112 # stdin comes from we skip the terminal case it can be handled by '-'
111 mode = os.fstat(0).st_mode
113 mode = os.fstat(0).st_mode
112 if stat.S_ISFIFO(mode):
114 if stat.S_ISFIFO(mode):
113 # "stdin is piped"
115 # "stdin is piped"
114 gist_content = sys.stdin.read()
116 gist_content = sys.stdin.read()
115 elif stat.S_ISREG(mode):
117 elif stat.S_ISREG(mode):
116 # "stdin is redirected"
118 # "stdin is redirected"
117 gist_content = sys.stdin.read()
119 gist_content = sys.stdin.read()
118 else:
120 else:
119 # "stdin is terminal"
121 # "stdin is terminal"
120 pass
122 pass
121
123
122 # make sure we don't upload binary stuff
124 # make sure we don't upload binary stuff
123 if gist_content and '\0' in gist_content:
125 if gist_content and '\0' in gist_content:
124 raise Exception('Error: binary files upload is not possible')
126 raise Exception('Error: binary files upload is not possible')
125
127
126 filename = os.path.basename(args.filename or filename)
128 filename = os.path.basename(args.filename or filename)
127 if gist_content:
129 if gist_content:
128 files = {
130 files = {
129 filename: {
131 filename: {
130 'content': gist_content,
132 'content': gist_content,
131 'lexer': None
133 'lexer': None
132 }
134 }
133 }
135 }
134
136
135 margs = dict(
137 margs = dict(
136 gist_lifetime=args.lifetime,
138 gist_lifetime=args.lifetime,
137 gist_description=args.description,
139 gist_description=args.description,
138 gist_type='private' if args.private else 'public',
140 gist_type='private' if args.private else 'public',
139 files=files
141 files=files
140 )
142 )
141
143
142 json_data = api_call(apikey, host, 'create_gist', **margs)['result']
144 json_data = api_call(apikey, host, 'create_gist', **margs)['result']
143 if args.format == FORMAT_JSON:
145 if args.format == FORMAT_JSON:
144 print json.dumps(json_data)
146 print json.dumps(json_data)
145 elif args.format == FORMAT_PRETTY:
147 elif args.format == FORMAT_PRETTY:
146 print 'Created %s gist %s' % (json_data['gist_type'],
148 print 'Created %s gist %s' % (json_data['gist_type'],
147 json_data['gist_url'])
149 json_data['gist_url'])
148 return 0
150 return 0
149
151
150
152
151 def main(argv=None):
153 def main(argv=None):
152 """
154 """
153 Main execution function for cli
155 Main execution function for cli
154
156
155 :param argv:
157 :param argv:
156 """
158 """
157 if argv is None:
159 if argv is None:
158 argv = sys.argv
160 argv = sys.argv
159
161
160 try:
162 try:
161 return _run(argv)
163 return _run(argv)
162 except Exception, e:
164 except Exception, e:
165 raise
163 print e
166 print e
164 return 1
167 return 1
165
168
166
169
167 if __name__ == '__main__':
170 if __name__ == '__main__':
168 sys.exit(main(sys.argv))
171 sys.exit(main(sys.argv))
General Comments 0
You need to be logged in to leave comments. Login now