blob: fb1807db371745fae6349393bd52a8b7a38a6fa1 [file] [log] [blame]
Basil Eljuse4b14afb2020-09-30 13:07:23 +01001# !/usr/bin/env python
2###############################################################################
3# Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
4#
5# SPDX-License-Identifier: BSD-3-Clause
6###############################################################################
7
8###############################################################################
9# FILE: clone_sources.py
10#
11# DESCRIPTION: Clone the source files for code coverage
12###############################################################################
13
14import os
15import subprocess
16import json
17import time
18from random import random
19
20
21def call_cmd(cmd, print_cmd=False):
22 """
23 Function that execute an os command and returns its output
24
25 :param cmd: OS command as string
26 :param print_cmd: Optional argument to print the command in stdout
27 :return: The string output of the os command
28 """
29 if print_cmd:
30 print("+" + cmd)
31 out = subprocess.check_output(cmd, shell=True)
32 return out
33
34
35def skip_source(output_dir, source, handler=None):
36 """
37 Function that handles overwriting source files
38
39 :param output_dir: Folder where to put the source files and folders
40 :param source: Dictionary with the information the source
41 :return: True if must skip the given source cloning False otherwise
42 """
43 location = os.path.join(output_dir, source['LOCATION'])
44 # Check if exists and have files
45 if os.path.isdir(location):
46 if not os.listdir(location):
47 if handler is not None:
48 return handler(source, "Directory exists and is empty")
49 else:
50 # By default send a warning and overwrite it
51 print(("WARNING!: Directory {} already exists and is "
52 "empty. Overwriting it...'").format(location))
53 os.rmdir(location)
54 return False
55 commit_id = call_cmd(("cd {} && git log -1 2>/dev/null | "
56 "grep commit | awk '{{print $2}}'").format(
57 location), print_cmd=True).strip()
58 if source['type'] == "git":
59 if commit_id == "":
60 # is not a git
61 if handler is not None:
62 return handler(source, "Directory exists and is not git")
63 else:
64 print(("WARNING!: Directory {} already exists and is not a"
65 " git repo: '{}'").format(location, source['URL']))
66 elif commit_id != source["COMMIT"].strip():
67 # there are mismatching commit id's
68 if handler is not None:
69 return handler(source, "Mismatch in gits")
70 else:
71 print(("WARNING!: Mismatch in git repo {}\nExpected {}, "
72 "Cloned {}").format(source['URL'], source['COMMIT'],
73 commit_id))
74 elif source['type'] == "http":
75 if handler is not None:
76 return handler(source,
77 "WARNING!: Directory already exists")
78 else:
79 print("WARNING!: Directory {} already exists".format(
80 location))
81 return True
82 return False
83
84
85class CloneSources(object):
86 """Class used to clone the source code needed to produce code coverage
87 reports.
88 """
89 def __init__(self, json_file):
90 self.json_file = json_file
91 self.json_data = None
92 self.load_json()
93
94 def load_json(self):
95 with open(self.json_file, "r") as json_file:
96 self.json_data = json.load(json_file)
97
98 def clone_repo(self, output_dir, overwrite_handler=None):
99 """
100 Clones or reproduces a folder with source code based in the
101 configuration in the json file
102
103 :param output_dir: Where to put the source files
104 :param overwrite_handler: Optional function to handle overwrites
105 """
106 if self.json_data is None:
107 self.load_json()
108 sources = []
109 try:
110 if 'parameters' in self.json_data:
111 sources = self.json_data['parameters']['sources']
112 elif 'configuration' in self.json_data:
113 sources = self.json_data['configuration']['sources']
114 else:
115 raise Exception("No correct format for json sources!")
116 except Exception as ex:
117 raise Exception(ex)
118
119 for source in sources:
120 if skip_source(output_dir, source, overwrite_handler):
121 continue
122 if source['type'] == "git":
123 git = source
124 url = git["URL"]
125 commit_id = git["COMMIT"]
126 output_loc = os.path.join(output_dir, git["LOCATION"])
127 cmd = "git clone {} {}".format(url, output_loc)
128 output = call_cmd(cmd)
129 if git['REFSPEC']:
130 call_cmd("cd {};git fetch -q origin {}".format(
131 output_loc, git['REFSPEC']))
132 if commit_id:
133 call_cmd("cd {};git checkout -q {}".format(
134 output_loc, commit_id))
135 else:
136 call_cmd("cd {};git checkout -q FETCH_HEAD".format(
137 output_loc))
138 elif source['type'] == 'http':
139 site = source
140 output_loc = os.path.join(output_dir, site["LOCATION"])
141 tmp_folder = os.path.join(output_dir,
142 "_tmp_{}_{}".format(time.time(),
143 random()))
144 call_cmd("mkdir -p {}".format(tmp_folder))
145 call_cmd("wget -q {} -P {}".format(
146 site['URL'], tmp_folder))
147 call_cmd("mkdir -p {}".format(output_loc))
148 if site['COMPRESSION'] == "xz":
149 call_cmd("cd {};tar -xzf $(basename {}) -C {}".format(
150 tmp_folder, site['URL'], output_loc))
151 call_cmd("rm -rf {}".format(tmp_folder))