aboutsummaryrefslogtreecommitdiff
path: root/scripts/send-error-report
blob: cd2e7f4b9db32a615fb9fb5328902bb5b7edd956 (plain)
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
#!/usr/bin/env python3

# Sends an error report (if the report-error class was enabled) to a
# remote server.
#
# Copyright (C) 2013 Intel Corporation
# Author: Andreea Proca <andreea.b.proca@intel.com>
# Author: Michael Wood <michael.g.wood@intel.com>

import urllib.request, urllib.error
import sys
import json
import os
import subprocess
import argparse
import logging

scripts_lib_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'lib')
sys.path.insert(0, scripts_lib_path)
import argparse_oe

version = "0.3"

log = logging.getLogger("send-error-report")
logging.basicConfig(format='%(levelname)s: %(message)s')

def getPayloadLimit(url):
    req = urllib.request.Request(url, None)
    try:
        response = urllib.request.urlopen(req)
    except urllib.error.URLError as e:
        # Use this opportunity to bail out if we can't even contact the server
        log.error("Could not contact server: " + url)
        log.error(e.reason)
        sys.exit(1)
    try:
        ret = json.loads(response.read())
        max_log_size = ret.get('max_log_size', 0)
        return int(max_log_size)
    except:
        pass

    return 0

def ask_for_contactdetails():
    print("Please enter your name and your email (optionally), they'll be saved in the file you send.")
    username = input("Name (required): ")
    email = input("E-mail (not required): ")
    return username, email

def edit_content(json_file_path):
    edit = input("Review information before sending? (y/n): ")
    if 'y' in edit or 'Y' in edit:
        editor = os.environ.get('EDITOR', None)
        if editor:
            subprocess.check_call([editor, json_file_path])
        else:
            log.error("Please set your EDITOR value")
            sys.exit(1)
        return True
    return False

def prepare_data(args):
    # attempt to get the max_log_size from the server's settings
    max_log_size = getPayloadLimit("http://"+args.server+"/ClientPost/JSON")

    if not os.path.isfile(args.error_file):
        log.error("No data file found.")
        sys.exit(1)

    home = os.path.expanduser("~")
    userfile = os.path.join(home, ".oe-send-error")

    try:
        with open(userfile, 'r') as userfile_fp:
            if len(args.name) == 0:
                args.name = userfile_fp.readline()
            else:
                #use empty readline to increment the fp
                userfile_fp.readline()

            if len(args.email) == 0:
                args.email = userfile_fp.readline()
    except:
        pass

    if args.assume_yes == True and len(args.name) == 0:
        log.error("Name needs to be provided either via "+userfile+" or as an argument (-n).")
        sys.exit(1)

    while len(args.name) <= 0 and len(args.name) < 50:
        print("\nName needs to be given and must not more than 50 characters.")
        args.name, args.email = ask_for_contactdetails()

    with open(userfile, 'w') as userfile_fp:
        userfile_fp.write(args.name.strip() + "\n")
        userfile_fp.write(args.email.strip() + "\n")

    with open(args.error_file, 'r') as json_fp:
        data = json_fp.read()

        jsondata = json.loads(data)
        jsondata['username'] = args.name.strip()
        jsondata['email'] = args.email.strip()
        jsondata['link_back'] = args.link_back.strip()
        # If we got a max_log_size then use this to truncate to get the last
        # max_log_size bytes from the end
        if max_log_size != 0:
            for fail in jsondata['failures']:
                if len(fail['log']) > max_log_size:
                    print("Truncating log to allow for upload")
                    fail['log'] = fail['log'][-max_log_size:]

        data = json.dumps(jsondata, indent=4, sort_keys=True)

    # Write back the result which will contain all fields filled in and
    # any post processing done on the log data
    with open(args.error_file, "w") as json_fp:
        if data:
            json_fp.write(data)


    if args.assume_yes == False and edit_content(args.error_file):
        #We'll need to re-read the content if we edited it
        with open(args.error_file, 'r') as json_fp:
            data = json_fp.read()

    return data.encode('utf-8')


def send_data(data, args):
    headers={'Content-type': 'application/json', 'User-Agent': "send-error-report/"+version}

    if args.json:
        url = "http://"+args.server+"/ClientPost/JSON/"
    else:
        url = "http://"+args.server+"/ClientPost/"

    req = urllib.request.Request(url, data=data, headers=headers)
    try:
        response = urllib.request.urlopen(req)
    except urllib.error.HTTPError as e:
        logging.error(e.reason)
        sys.exit(1)

    print(response.read().decode('utf-8'))


if __name__ == '__main__':
    arg_parse = argparse_oe.ArgumentParser(description="This scripts will send an error report to your specified error-report-web server.")

    arg_parse.add_argument("error_file",
                           help="Generated error report file location",
                           type=str)

    arg_parse.add_argument("-y",
                           "--assume-yes",
                           help="Assume yes to all queries and do not prompt",
                           action="store_true")

    arg_parse.add_argument("-s",
                           "--server",
                           help="Server to send error report to",
                           type=str,
                           default="errors.yoctoproject.org")

    arg_parse.add_argument("-e",
                           "--email",
                           help="Email address to be used for contact",
                           type=str,
                           default="")

    arg_parse.add_argument("-n",
                           "--name",
                           help="Submitter name used to identify your error report",
                           type=str,
                           default="")

    arg_parse.add_argument("-l",
                           "--link-back",
                           help="A url to link back to this build from the error report server",
                           type=str,
                           default="")

    arg_parse.add_argument("-j",
                           "--json",
                           help="Return the result in json format, silences all other output",
                           action="store_true")



    args = arg_parse.parse_args()

    if (args.json == False):
        print("Preparing to send errors to: "+args.server)

    data = prepare_data(args)
    send_data(data, args)

    sys.exit(0)