def _get_filepath(cp): def get_key_filepath(key): for i in range(len(dir_infos)): info = dir_infos[i] if key in info.filemap: basepath = basepaths[i] return path.join(basepath, info.filemap[key]) return None cp_key = tuple([cp]) cp_key = unicode_data.get_canonical_emoji_sequence(cp_key) or cp_key fp = get_key_filepath(cp_key) if not fp: if cp_key in aliases: fp = get_key_filepath(aliases[cp_key]) else: print('no alias for %s' % unicode_data.seq_to_string(cp_key)) if not fp: print('no part for %s in %s' % (unicode_data.seq_to_string(cp_key), unicode_data.seq_to_string(key_tuple))) return fp
def _parse_annotation_file(afile): """Parse file and return a map from sequences to one of 'ok', 'warning', or 'error'. The file format consists of two kinds of lines. One defines the annotation to apply, it consists of the text 'annotation:' followed by one of 'ok', 'warning', or 'error'. The other defines a sequence that should get the most recently defined annotation, this is a series of codepoints expressed in hex separated by spaces. The initial default annotation is 'error'. '#' starts a comment to end of line, blank lines are ignored. """ annotations = {} line_re = re.compile(r'annotation:\s*(ok|warning|error)|([0-9a-f ]+)') annotation = 'error' with open(afile, 'r') as f: for line in f: line = line.strip() if not line or line[0] == '#': continue m = line_re.match(line) if not m: raise Exception('could not parse annotation "%s"' % line) new_annotation = m.group(1) if new_annotation: annotation = new_annotation else: seq = tuple([int(s, 16) for s in m.group(2).split()]) canonical_seq = unicode_data.get_canonical_emoji_sequence(seq) if canonical_seq: seq = canonical_seq if seq in annotations: raise Exception( 'duplicate sequence %s in annotations' % unicode_data.seq_to_string(seq)) annotations[seq] = annotation return annotations
def add_aliases(srcdir, dstdir, aliasfile, prefix, ext, replace=False, copy=False, canonical_names=False, dry_run=False): """Use aliasfile to create aliases of files in srcdir matching prefix/ext in dstdir. If dstdir is null, use srcdir as dstdir. If replace is false and a file already exists in dstdir, report and do nothing. If copy is false create a symlink, else create a copy. If canonical_names is true, check all source files and generate aliases/copies using the canonical name if different from the existing name. If dry_run is true, report what would be done. Dstdir will be created if necessary, even if dry_run is true.""" if not path.isdir(srcdir): print('%s is not a directory' % srcdir, file=sys.stderr) return if not dstdir: dstdir = srcdir elif not path.isdir(dstdir): os.makedirs(dstdir) prefix_len = len(prefix) suffix_len = len(ext) + 1 filenames = [ path.basename(f) for f in glob.glob(path.join(srcdir, '%s*.%s' % (prefix, ext))) ] seq_to_file = { str_to_seq(name[prefix_len:-suffix_len]): name for name in filenames } aliases = read_emoji_aliases(aliasfile) aliases_to_create = {} aliases_to_replace = [] alias_exists = False def check_alias_seq(seq): alias_str = seq_to_str(seq) alias_name = '%s%s.%s' % (prefix, alias_str, ext) alias_path = path.join(dstdir, alias_name) if path.exists(alias_path): if replace: aliases_to_replace.append(alias_name) else: print('alias %s exists' % alias_str, file=sys.stderr) alias_exists = True return None return alias_name canonical_to_file = {} for als, trg in sorted(aliases.items()): if trg not in seq_to_file: print('target %s for %s does not exist' % (seq_to_str(trg), seq_to_str(als)), file=sys.stderr) continue alias_name = check_alias_seq(als) if alias_name: target_file = seq_to_file[trg] aliases_to_create[alias_name] = target_file if canonical_names: canonical_seq = unicode_data.get_canonical_emoji_sequence(als) if canonical_seq and canonical_seq != als: canonical_alias_name = check_alias_seq(canonical_seq) if canonical_alias_name: canonical_to_file[canonical_alias_name] = target_file if canonical_names: print('adding %d canonical aliases' % len(canonical_to_file)) for seq, f in seq_to_file.iteritems(): canonical_seq = unicode_data.get_canonical_emoji_sequence(seq) if canonical_seq and canonical_seq != seq: alias_name = check_alias_seq(canonical_seq) if alias_name: canonical_to_file[alias_name] = f print('adding %d total canonical sequences' % len(canonical_to_file)) aliases_to_create.update(canonical_to_file) if replace: if not dry_run: for k in sorted(aliases_to_replace): os.remove(path.join(dstdir, k)) print('replacing %d files' % len(aliases_to_replace)) elif alias_exists: print('aborting, aliases exist.', file=sys.stderr) return for k, v in sorted(aliases_to_create.items()): if dry_run: msg = 'replace ' if k in aliases_to_replace else '' print('%s%s -> %s' % (msg, k, v)) else: try: if copy: shutil.copy2(path.join(srcdir, v), path.join(dstdir, k)) else: # fix this to create relative symlinks if srcdir == dstdir: os.symlink(v, path.join(dstdir, k)) else: raise Exception( 'can\'t create cross-directory symlinks yet') except Exception as e: print('failed to create %s -> %s' % (k, v), file=sys.stderr) raise Exception('oops, ' + str(e)) print('created %d %s' % (len(aliases_to_create), 'copies' if copy else 'symlinks'))
def _generate_content(basedir, font, dir_infos, limit, annotate, standalone, colors): """Generate an html table for the infos. basedir is the parent directory of the content, filenames will be made relative to this if underneath it, else absolute. If limit is true and there are multiple dirs, limit the set of sequences to those in the first dir. If font is not none, generate columns for the text rendered in the font before other columns. if annotate is not none, highlight sequences that appear in this set.""" if len(dir_infos) == 1 or limit: all_keys = frozenset(dir_infos[0].filemap.keys()) else: all_keys = _merge_keys([info.filemap for info in dir_infos]) basedir = path.abspath(path.expanduser(basedir)) if not path.isdir(basedir): os.makedirs(basedir) basepaths = [] if standalone: # auxiliary images are used in the decomposition of multi-part emoji but # aren't part of main set. e.g. if we have female basketball player # color-3 we want female, basketball player, and color-3 images available # even if they aren't part of the target set. aux_info = _collect_aux_info(dir_infos, all_keys) # create image subdirectories in target dir, copy image files to them, # and adjust paths for i, info in enumerate(dir_infos): subdir = '%02d' % i dstdir = path.join(basedir, subdir) if not path.isdir(dstdir): os.mkdir(dstdir) aux_keys = aux_info[i] copy_keys = all_keys if not aux_keys else (all_keys | aux_keys) srcdir = info.directory filemap = info.filemap for key in copy_keys: if key in filemap: filename = filemap[key] srcfile = path.join(srcdir, filename) dstfile = path.join(dstdir, filename) shutil.copy2(srcfile, dstfile) basepaths.append(subdir) else: for srcdir, _, _ in dir_infos: abs_srcdir = path.abspath(path.expanduser(srcdir)) if abs_srcdir == basedir: dirspec = '' elif abs_srcdir.startswith(basedir): dirspec = abs_srcdir[len(basedir) + 1:] else: dirspec = abs_srcdir basepaths.append(dirspec) lines = ['<table>'] header_row = [''] if font: header_row.extend(['Emoji ltr', 'Emoji rtl']) header_row.extend([info.title for info in dir_infos]) if len(colors) > 1: header_row.extend([dir_infos[-1].title] * (len(colors) - 1)) header_row.extend(['Sequence', 'Name']) lines.append('<th>'.join(header_row)) for key in sorted(all_keys): row = [] canonical_key = unicode_data.get_canonical_emoji_sequence(key) if not canonical_key: canonical_key = key row.extend( _generate_row_cells(key, canonical_key, font, dir_infos, basepaths, colors)) row.append(_get_desc(canonical_key, dir_infos, basepaths)) row.append(_get_name(canonical_key, annotate)) try: lines.append(''.join(row)) except: raise Exception('couldn\'t decode %s' % row) return '\n <tr>'.join(lines) + '\n</table>'
def canon(seq): return unicode_data.get_canonical_emoji_sequence(seq) or seq
def add_aliases( srcdir, dstdir, aliasfile, prefix, ext, replace=False, copy=False, canonical_names=False, dry_run=False): """Use aliasfile to create aliases of files in srcdir matching prefix/ext in dstdir. If dstdir is null, use srcdir as dstdir. If replace is false and a file already exists in dstdir, report and do nothing. If copy is false create a symlink, else create a copy. If canonical_names is true, check all source files and generate aliases/copies using the canonical name if different from the existing name. If dry_run is true, report what would be done. Dstdir will be created if necessary, even if dry_run is true.""" if not path.isdir(srcdir): print('%s is not a directory' % srcdir, file=sys.stderr) return if not dstdir: dstdir = srcdir elif not path.isdir(dstdir): os.makedirs(dstdir) prefix_len = len(prefix) suffix_len = len(ext) + 1 filenames = [path.basename(f) for f in glob.glob(path.join(srcdir, '%s*.%s' % (prefix, ext)))] seq_to_file = { str_to_seq(name[prefix_len:-suffix_len]) : name for name in filenames} aliases = read_emoji_aliases(aliasfile) aliases_to_create = {} aliases_to_replace = [] alias_exists = False def check_alias_seq(seq): alias_str = seq_to_str(seq) alias_name = '%s%s.%s' % (prefix, alias_str, ext) alias_path = path.join(dstdir, alias_name) if path.exists(alias_path): if replace: aliases_to_replace.append(alias_name) else: print('alias %s exists' % alias_str, file=sys.stderr) alias_exists = True return None return alias_name canonical_to_file = {} for als, trg in sorted(aliases.items()): if trg not in seq_to_file: print('target %s for %s does not exist' % ( seq_to_str(trg), seq_to_str(als)), file=sys.stderr) continue alias_name = check_alias_seq(als) if alias_name: target_file = seq_to_file[trg] aliases_to_create[alias_name] = target_file if canonical_names: canonical_seq = unicode_data.get_canonical_emoji_sequence(als) if canonical_seq and canonical_seq != als: canonical_alias_name = check_alias_seq(canonical_seq) if canonical_alias_name: canonical_to_file[canonical_alias_name] = target_file if canonical_names: print('adding %d canonical aliases' % len(canonical_to_file)) for seq, f in seq_to_file.iteritems(): canonical_seq = unicode_data.get_canonical_emoji_sequence(seq) if canonical_seq and canonical_seq != seq: alias_name = check_alias_seq(canonical_seq) if alias_name: canonical_to_file[alias_name] = f print('adding %d total canonical sequences' % len(canonical_to_file)) aliases_to_create.update(canonical_to_file) if replace: if not dry_run: for k in sorted(aliases_to_replace): os.remove(path.join(dstdir, k)) print('replacing %d files' % len(aliases_to_replace)) elif alias_exists: print('aborting, aliases exist.', file=sys.stderr) return for k, v in sorted(aliases_to_create.items()): if dry_run: msg = 'replace ' if k in aliases_to_replace else '' print('%s%s -> %s' % (msg, k, v)) else: try: if copy: shutil.copy2(path.join(srcdir, v), path.join(dstdir, k)) else: # fix this to create relative symlinks if srcdir == dstdir: os.symlink(v, path.join(dstdir, k)) else: raise Exception('can\'t create cross-directory symlinks yet') except Exception as e: print('failed to create %s -> %s' % (k, v), file=sys.stderr) raise Exception('oops, ' + str(e)) print('created %d %s' % ( len(aliases_to_create), 'copies' if copy else 'symlinks'))