- Arguments:
- defconfig: Board (defconfig) name
-
- Returns:
- Return True on success or False on fail
- """
- if self.occupied:
- return False
-
- with open(os.path.join(self.build_dir, '.tmp_defconfig'), 'w') as f:
- for line in open(os.path.join(CONFIG_DIR, defconfig)):
- colon = line.find(':CONFIG_')
- if colon == -1:
- f.write(line)
- else:
- f.write(line[colon + 1:])
-
- self.ps = subprocess.Popen([os.path.join('scripts', 'kconfig', 'conf'),
- '--defconfig=.tmp_defconfig', 'Kconfig'],
- stdout=self.devnull,
- cwd=self.build_dir,
- env=self.env)
-
- self.defconfig = defconfig
- self.occupied = True
- return True
-
- def wait(self):
- """Wait until the current subprocess finishes."""
- while self.occupied and self.ps.poll() == None:
- time.sleep(SLEEP_TIME)
- self.occupied = False
-
- def poll(self):
- """Check if the subprocess is running and invoke the .config
- parser if the subprocess is terminated.
-
- Returns:
- Return True if the subprocess is terminated, False otherwise
- """
- if not self.occupied:
- return True
- if self.ps.poll() == None:
- return False
- if self.ps.poll() == 0:
- self.parser.parse(self.defconfig)
- else:
- print >> sys.stderr, ("WARNING: failed to process '%s'. skip." %
- self.defconfig)
- self.occupied = False
- return True
-
-class Slots:
-
- """Controller of the array of subprocess slots."""
-
- def __init__(self, jobs, output, maintainers_database):
- """Create a new slots controller.
-
- Arguments:
- jobs: A number of slots to instantiate
- output: File object which the result is written to
- maintainers_database: An instance of class MaintainersDatabase
- """
- self.slots = []
- devnull = get_devnull()
- make_cmd = get_make_cmd()
- for i in range(jobs):
- self.slots.append(Slot(output, maintainers_database,
- devnull, make_cmd))
- for slot in self.slots:
- slot.wait()
-
- def add(self, defconfig):
- """Add a new subprocess if a vacant slot is available.
-
- Arguments:
- defconfig: Board (defconfig) name
-
- Returns:
- Return True on success or False on fail
- """
- for slot in self.slots:
- if slot.add(defconfig):
- return True
- return False
-
- def available(self):
- """Check if there is a vacant slot.
-
- Returns:
- Return True if a vacant slot is found, False if all slots are full
- """
- for slot in self.slots:
- if slot.poll():
- return True
- return False
-
- def empty(self):
- """Check if all slots are vacant.
-
- Returns:
- Return True if all slots are vacant, False if at least one slot
- is running
- """
- ret = True
- for slot in self.slots:
- if not slot.poll():
- ret = False
- return ret
-
-class Indicator:
-
- """A class to control the progress indicator."""
-
- MIN_WIDTH = 15
- MAX_WIDTH = 70
-
- def __init__(self, total):
- """Create an instance.
-
- Arguments:
- total: A number of boards
- """
- self.total = total
- self.cur = 0
- width = get_terminal_columns()
- width = min(width, self.MAX_WIDTH)
- width -= self.MIN_WIDTH
- if width > 0:
- self.enabled = True
- else:
- self.enabled = False
- self.width = width
-
- def inc(self):
- """Increment the counter and show the progress bar."""
- if not self.enabled:
- return
- self.cur += 1
- arrow_len = self.width * self.cur // self.total
- msg = '%4d/%d [' % (self.cur, self.total)
- msg += '=' * arrow_len + '>' + ' ' * (self.width - arrow_len) + ']'
- sys.stdout.write('\r' + msg)
- sys.stdout.flush()
-
-class BoardsFileGenerator:
-
- """Generator of boards.cfg."""
-
- def __init__(self):
- """Prepare basic things for generating boards.cfg."""
- # All the defconfig files to be processed
- defconfigs = []
- for (dirpath, dirnames, filenames) in os.walk(CONFIG_DIR):
- dirpath = dirpath[len(CONFIG_DIR) + 1:]
- for filename in fnmatch.filter(filenames, '*_defconfig'):
- if fnmatch.fnmatch(filename, '.*'):
- continue
- defconfigs.append(os.path.join(dirpath, filename))
- self.defconfigs = defconfigs
- self.indicator = Indicator(len(defconfigs))
-
- # Parse all the MAINTAINERS files
- maintainers_database = MaintainersDatabase()
- for (dirpath, dirnames, filenames) in os.walk('.'):
- if 'MAINTAINERS' in filenames:
- maintainers_database.parse_file(os.path.join(dirpath,
- 'MAINTAINERS'))
- self.maintainers_database = maintainers_database
-
- def __del__(self):
- """Delete the incomplete boards.cfg
-
- This destructor deletes boards.cfg if the private member 'in_progress'
- is defined as True. The 'in_progress' member is set to True at the
- beginning of the generate() method and set to False at its end.
- So, in_progress==True means generating boards.cfg was terminated
- on the way.
- """
-
- if hasattr(self, 'in_progress') and self.in_progress:
- try:
- os.remove(BOARD_FILE)
- except OSError as exception:
- # Ignore 'No such file or directory' error
- if exception.errno != errno.ENOENT:
- raise
- print 'Removed incomplete %s' % BOARD_FILE
-
- def generate(self, jobs):
- """Generate boards.cfg
-
- This method sets the 'in_progress' member to True at the beginning
- and sets it to False on success. The boards.cfg should not be
- touched before/after this method because 'in_progress' is used
- to detect the incomplete boards.cfg.
-
- Arguments:
- jobs: The number of jobs to run simultaneously
- """
-
- self.in_progress = True
- print 'Generating %s ... (jobs: %d)' % (BOARD_FILE, jobs)
-
- # Output lines should be piped into the reformat tool
- reformat_process = subprocess.Popen(REFORMAT_CMD,
- stdin=subprocess.PIPE,
- stdout=open(BOARD_FILE, 'w'))
- pipe = reformat_process.stdin
- pipe.write(COMMENT_BLOCK)
-
- slots = Slots(jobs, pipe, self.maintainers_database)
-
- # Main loop to process defconfig files:
- # Add a new subprocess into a vacant slot.
- # Sleep if there is no available slot.
- for defconfig in self.defconfigs:
- while not slots.add(defconfig):
- while not slots.available():
- # No available slot: sleep for a while
- time.sleep(SLEEP_TIME)
- self.indicator.inc()
-
- # wait until all the subprocesses finish
- while not slots.empty():
- time.sleep(SLEEP_TIME)
- print ''
-
- # wait until the reformat tool finishes
- reformat_process.communicate()
- if reformat_process.returncode != 0:
- sys.exit('"%s" failed' % REFORMAT_CMD[0])
-
- self.in_progress = False
-
-def gen_boards_cfg(jobs=1, force=False):
- """Generate boards.cfg file.
-
- The incomplete boards.cfg is deleted if an error (including
- the termination by the keyboard interrupt) occurs on the halfway.