#!/usr/bin/env python3 # # Copyright 2017 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import print_function import argparse import glob import os from os import path import shutil import sys from nototools import unicode_data """Create aliases in target directory. In addition to links/copies named with aliased sequences, this can also create canonically named aliases/copies, if requested.""" DATA_ROOT = path.dirname(path.abspath(__file__)) def str_to_seq(seq_str): res = [int(s, 16) for s in seq_str.split('_')] if 0xfe0f in res: print('0xfe0f in file name: %s' % seq_str) res = [x for x in res if x != 0xfe0f] return tuple(res) def seq_to_str(seq): return '_'.join('%04x' % cp for cp in seq) def read_default_unknown_flag_aliases(): unknown_flag_path = path.join(DATA_ROOT, 'unknown_flag_aliases.txt') return read_emoji_aliases(unknown_flag_path) def read_default_emoji_aliases(): alias_path = path.join(DATA_ROOT, 'emoji_aliases.txt') return read_emoji_aliases(alias_path) def read_emoji_aliases(filename): result = {} with open(filename, 'r') as f: for line in f: ix = line.find('#') if (ix > -1): line = line[:ix] line = line.strip() if not line: continue als, trg = (s.strip() for s in line.split(';')) try: als_seq = tuple([int(x, 16) for x in als.split('_')]) trg_seq = tuple([int(x, 16) for x in trg.split('_')]) except: print('cannot process alias %s -> %s' % (als, trg)) continue result[als_seq] = trg_seq return result 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 main(): parser = argparse.ArgumentParser() parser.add_argument( '-s', '--srcdir', help='directory containing files to alias', required=True, metavar='dir') parser.add_argument( '-d', '--dstdir', help='directory to write aliases, default srcdir', metavar='dir') parser.add_argument( '-a', '--aliasfile', help='alias file (default emoji_aliases.txt)', metavar='file', default='emoji_aliases.txt') parser.add_argument( '-p', '--prefix', help='file name prefix (default emoji_u)', metavar='pfx', default='emoji_u') parser.add_argument( '-e', '--ext', help='file name extension (default png)', choices=['ai', 'png', 'svg'], default='png') parser.add_argument( '-r', '--replace', help='replace existing files/aliases', action='store_true') parser.add_argument( '-c', '--copy', help='create a copy of the file, not a symlink', action='store_true') parser.add_argument( '--canonical_names', help='include extra copies with canonical names ' '(including fe0f emoji presentation character)', action='store_true'); parser.add_argument( '-n', '--dry_run', help='print out aliases to create only', action='store_true') args = parser.parse_args() add_aliases( args.srcdir, args.dstdir, args.aliasfile, args.prefix, args.ext, args.replace, args.copy, args.canonical_names, args.dry_run) if __name__ == '__main__': main()