Ejemplo n.º 1
0
def main(args):
    parser = argparse.ArgumentParser(
        prog='packer.py',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description='Pack obfuscated scripts',
        epilog=__doc__,
    )
    add_arguments(parser)
    packer(parser.parse_args(args))
Ejemplo n.º 2
0
def main(args):
    parser = argparse.ArgumentParser(
        prog='pyarmor',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description=__doc__,
        epilog='See "pyarmor <command> -h" for more information '
               'on a specific command.\n\nMore usage refer to '
               'https://pyarmor.readthedocs.io'
    )
    parser.add_argument('-v', '--version', action='version',
                        version=_version_info())
    parser.add_argument('-q', '--silent', action='store_true',
                        help='Suppress all normal output')

    subparsers = parser.add_subparsers(
        title='The most commonly used pyarmor commands are',
        metavar=''
    )

    #
    # Command: obfuscate
    #
    cparser = subparsers.add_parser(
        'obfuscate',
        aliases=['o'],
        epilog=_obfuscate.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Obfuscate python scripts')
    cparser.add_argument('-O', '--output', default='dist', metavar='PATH')
    cparser.add_argument('-r', '--recursive', action='store_true',
                         help='Search scripts in recursive mode')
    cparser.add_argument('--exclude', metavar='PATH', action='append',
                         help='Exclude the path in recursive mode. '
                         'Multiple paths are allowed, separated by ",". '
                         'Or use this option multiple times')
    cparser.add_argument('--exact', action='store_true',
                         help='Only obfusate list scripts')
    cparser.add_argument('--no-bootstrap', action='store_true',
                         help='Do not insert bootstrap code to entry script')
    cparser.add_argument('--no-cross-protection', action='store_true',
                         help='Do not insert cross protection code to entry '
                         'script')
    cparser.add_argument('scripts', metavar='SCRIPT', nargs='*',
                         help='List scripts to obfuscated, the first script '
                         'is entry script')
    cparser.add_argument('-s', '--src', metavar='PATH',
                         help='Base path for searching scripts')
    cparser.add_argument('-e', '--entry', metavar='SCRIPT',
                         help=argparse.SUPPRESS)
    cparser.add_argument('--cross-protection', choices=(0, 1),
                         help=argparse.SUPPRESS)
    cparser.add_argument('--plugin', dest='plugins', action='append',
                         help='Insert extra code to entry script')
    cparser.add_argument('--restrict', type=int, choices=range(5),
                         default=1, help='Set restrict mode')
    cparser.add_argument('--capsule', help=argparse.SUPPRESS)
    cparser.add_argument('--platform', help='Distribute obfuscated scripts '
                         'to other platform')
    cparser.add_argument('--advanced', nargs='?', const=1, type=int,
                         default=0, choices=(0, 1),
                         help='Enable advanced mode')
    cparser.add_argument('--package-runtime', choices=(0, 1, 2), type=int,
                         default=1,
                         help='Save runtime files as a package or not')
    cparser.add_argument('-n', '--no-runtime', action='store_true',
                         help='DO NOT generate runtime files')
    cparser.set_defaults(func=_obfuscate)

    #
    # Command: license
    #
    cparser = subparsers.add_parser(
        'licenses',
        aliases=['l'],
        epilog=_licenses.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Generate new licenses for obfuscated scripts'
    )
    cparser.add_argument('codes', nargs='+', metavar='CODE',
                         help='Registration code for this license')
    group = cparser.add_argument_group('Bind license to hardware')
    group.add_argument('-e', '--expired', metavar='YYYY-MM-DD',
                       help='Expired date for this license')
    group.add_argument('-d', '--bind-disk', metavar='SN',
                       help='Bind license to serial number of harddisk')
    group.add_argument('-4', '--bind-ipv4', metavar='a.b.c.d',
                       help='Bind license to ipv4 addr')
    # group.add_argument('-6', '--bind-ipv6', metavar='a:b:c:d',
    #                    help='Bind license to ipv6 addr')
    group.add_argument('-m', '--bind-mac', metavar='x:x:x:x',
                       help='Bind license to mac addr')
    group.add_argument('-x', '--bind-data', metavar='DATA', help='Pass extra '
                       'data to license, used to extend license type')
    group.add_argument('--bind-domain', metavar='DOMAIN',
                       help='Bind license to domain name')
    group.add_argument('--bind-file', metavar='filename;target_filename',
                       help=argparse.SUPPRESS)
    cparser.add_argument('-P', '--project', default='', help=argparse.SUPPRESS)
    cparser.add_argument('-C', '--capsule', help=argparse.SUPPRESS)
    cparser.add_argument('-O', '--output', help='Output path')
    cparser.add_argument('--disable-restrict-mode', action='store_true',
                         help='Disable all the restrict modes')
    cparser.add_argument('--restrict', type=int, choices=(0, 1),
                         default=1, help=argparse.SUPPRESS)

    cparser.set_defaults(func=_licenses)

    #
    # Command: pack
    #
    cparser = subparsers.add_parser(
        'pack',
        aliases=['p'],
        epilog=packer.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Pack obfuscated scripts to one bundle'
    )
    packer.add_arguments(cparser)
    cparser.set_defaults(func=packer.packer)

    #
    # Command: init
    #
    cparser = subparsers.add_parser(
        'init',
        aliases=['i'],
        epilog=_init.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Create a project to manage obfuscated scripts'
    )
    cparser.add_argument('-t', '--type', default='auto',
                         choices=('auto', 'app', 'pkg'))
    cparser.add_argument('-e', '--entry',
                         help='Entry script of this project')
    cparser.add_argument('-s', '--src', default='',
                         help='Base path of python scripts')
    cparser.add_argument('--capsule', help=argparse.SUPPRESS)
    cparser.add_argument('--child', type=int, help=argparse.SUPPRESS)
    cparser.add_argument('project', nargs='?', default='', help='Project path')
    cparser.set_defaults(func=_init)

    #
    # Command: config
    #
    cparser = subparsers.add_parser(
        'config',
        aliases=['c'],
        epilog=_config.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Update project settings')
    cparser.add_argument('project', nargs='?', metavar='PATH',
                         default='', help='Project path')
    cparser.add_argument('--name')
    cparser.add_argument('--title')
    cparser.add_argument('--src')
    cparser.add_argument('--output')
    cparser.add_argument('--capsule', help=argparse.SUPPRESS)
    cparser.add_argument('--platform', help=argparse.SUPPRESS)
    cparser.add_argument('--manifest', metavar='TEMPLATE',
                         help='Manifest template string')
    cparser.add_argument('--entry', metavar='SCRIPT',
                         help='Entry script of this project')
    cparser.add_argument('--is-package', type=int, choices=(0, 1))
    cparser.add_argument('--disable-restrict-mode', type=int, choices=(0, 1),
                         help=argparse.SUPPRESS)
    cparser.add_argument('--restrict-mode', type=int, choices=range(5),
                         help='Set restrict mode')
    cparser.add_argument('--obf-module-mode', choices=Project.OBF_MODULE_MODE,
                         help='[DEPRECATED] Use --obf-mod instead')
    cparser.add_argument('--obf-code-mode', choices=Project.OBF_CODE_MODE,
                         help='[DEPRECATED] Use --obf-code and --wrap-mode'
                              ' instead')
    cparser.add_argument('--obf-mod', type=int, choices=(0, 1))
    cparser.add_argument('--obf-code', type=int, choices=(0, 1, 2))
    cparser.add_argument('--wrap-mode', type=int, choices=(0, 1))
    cparser.add_argument('--cross-protection', type=int, choices=(0, 1))
    cparser.add_argument('--runtime-path', metavar="RPATH")
    cparser.add_argument('--plugin', dest='plugins', action='append',
                         help='Insert extra code to entry script')
    cparser.add_argument('--advanced-mode', type=int, choices=(0, 1))
    cparser.add_argument('--package-runtime', choices=(0, 1, 2), type=int,
                         help='Save runtime files as a package or not')
    cparser.set_defaults(func=_config)

    #
    # Command: build
    #
    cparser = subparsers.add_parser(
        'build',
        aliases=['b'],
        epilog=_build.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Obfuscate all the scripts in the project')
    cparser.add_argument('project', nargs='?', metavar='PATH', default='',
                         help='Project path')
    cparser.add_argument('-B', '--force', action='store_true',
                         help='Force to obfuscate all scripts')
    cparser.add_argument('-r', '--only-runtime', action='store_true',
                         help='Generate extra runtime files only')
    cparser.add_argument('-n', '--no-runtime', action='store_true',
                         help='DO NOT generate runtime files')
    cparser.add_argument('-O', '--output',
                         help='Output path, override project configuration')
    cparser.add_argument('--platform', help='Distribute obfuscated scripts '
                         'to other platform')
    cparser.add_argument('--package-runtime', choices=(0, 1, 2), type=int,
                         help='Save runtime files as a package or not')
    cparser.set_defaults(func=_build)

    #
    # Command: info
    #
    cparser = subparsers.add_parser(
        'info',
        epilog=_info.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Show project information'
    )
    cparser.add_argument('project', nargs='?', metavar='PATH',
                         default='', help='Project path')
    cparser.set_defaults(func=_info)

    #
    # Command: check
    #
    cparser = subparsers.add_parser(
        'check',
        epilog=_check.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Check consistency of project')
    cparser.add_argument('project', nargs='?', metavar='PATH',
                         default='', help='Project path')
    cparser.set_defaults(func=_check)

    #
    # Command: hdinfo
    #
    cparser = subparsers.add_parser(
        'hdinfo',
        epilog=_hdinfo.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Show hardware information'
    )
    cparser.set_defaults(func=_hdinfo)

    #
    # Command: benchmark
    #
    cparser = subparsers.add_parser(
        'benchmark',
        epilog=_benchmark.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Run benchmark test in current machine'
    )
    cparser.add_argument('-m', '--obf-mod', choices=(0, 1),
                         default=1, type=int)
    cparser.add_argument('-c', '--obf-code', choices=(0, 1, 2),
                         default=1, type=int)
    cparser.add_argument('-w', '--wrap-mode', choices=(0, 1),
                         default=1, type=int)
    cparser.add_argument('--debug', action='store_true',
                         help='Do not clean the test scripts'
                              'generated in real time')
    cparser.set_defaults(func=_benchmark)

    #
    # Command: capsule
    #
    cparser = subparsers.add_parser(
        'capsule',
        epilog=_capsule.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        add_help=False)
    cparser.add_argument('-f', '--force', action='store_true',
                         help='Force update public capsule even if it exists')
    cparser.add_argument('path', nargs='?', default=os.path.expanduser('~'),
                         help='Path to save capsule, default is home path')
    cparser.set_defaults(func=_capsule)

    #
    # Command: register
    #
    cparser = subparsers.add_parser(
        'register',
        epilog=_register.__doc__ + purchase_info,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Make registration keyfile work')
    group = cparser.add_mutually_exclusive_group()
    group.add_argument('filename', nargs='?', metavar='KEYFILE',
                       help='Filename of registration keyfile')
    cparser.set_defaults(func=_register)

    #
    # Command: download
    #
    cparser = subparsers.add_parser(
        'download',
        epilog=_download.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Download platform-dependent dynamic libraries')
    cparser.add_argument('-O', '--output', metavar='NAME',
                         help='Save downloaded file to another path')
    cparser.add_argument('--url',
                         help='Use this mirror site other than default site')
    group = cparser.add_mutually_exclusive_group()
    group.add_argument('--list', nargs='?', const='', dest='pattern',
                       help='List all the available platforms')
    group.add_argument('platid', nargs='?',
                       help='Download dynamic library by platform id')
    cparser.set_defaults(func=_download)

    #
    # Command: runtime
    #
    cparser = subparsers.add_parser(
        'runtime',
        epilog=_runtime.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Generate runtime package separately')
    cparser.add_argument('-O', '--output', metavar='PATH', default='dist',
                         help='Output path, default is "%(default)s"')
    cparser.add_argument('-n', '--no-package', action='store_true',
                         help='Generate runtime files without package')
    cparser.add_argument('-L', '--with-license', metavar='license',
                         help='Replace default license with this file')
    cparser.add_argument('--platform', help='Generate runtime package '
                         'for specified platform')
    cparser.add_argument('pkgname', nargs='?', default='pytransform',
                         help=argparse.SUPPRESS)
    cparser.set_defaults(func=_runtime)

    args = parser.parse_args(args)
    if args.silent:
        logging.getLogger().setLevel(100)

    if not hasattr(args, 'func'):
        parser.print_help()
        return

    logging.info(_version_info(verbose=0))
    logging.debug('PyArmor install path: %s', PYARMOR_PATH)

    args.func(args)
Ejemplo n.º 3
0
def _parser():
    parser = argparse.ArgumentParser(
        prog='pyarmor',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description=__doc__,
        epilog='See "pyarmor <command> -h" for more information '
               'on a specific command.\n\nMore usage refer to '
               'https://pyarmor.readthedocs.io'
    )
    parser.add_argument('-v', '--version', action='version',
                        version=_version_action)
    parser.add_argument('-q', '--silent', action='store_true',
                        help='Suppress all normal output')
    parser.add_argument('-d', '--debug', action='store_true',
                        help='Print exception traceback and debugging message')

    subparsers = parser.add_subparsers(
        title='The most commonly used pyarmor commands are',
        metavar=''
    )

    #
    # Command: obfuscate
    #
    cparser = subparsers.add_parser(
        'obfuscate',
        aliases=['o'],
        epilog=_obfuscate.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Obfuscate python scripts')
    cparser.add_argument('-O', '--output', default='dist', metavar='PATH',
                         help='Output path, default is "%(default)s"')
    cparser.add_argument('-r', '--recursive', action='store_true',
                         help='Search scripts in recursive mode')
    cparser.add_argument('--exclude', metavar='PATH', action='append',
                         help='Exclude the path in recursive mode. '
                         'Multiple paths are allowed, separated by ",". '
                         'Or use this option multiple times')
    cparser.add_argument('--exact', action='store_true',
                         help='Only obfusate list scripts')
    cparser.add_argument('--no-bootstrap', action='store_true',
                         help='Do not insert bootstrap code to entry script')
    cparser.add_argument('--bootstrap', '--bootstrap-code',
                         dest='bootstrap_code',
                         type=int, default=1, choices=(0, 1, 2, 3),
                         help='How to insert bootstrap code to entry script')
    cparser.add_argument('--no-cross-protection', action='store_true',
                         help='Do not insert cross protection code to entry '
                         'script')
    cparser.add_argument('scripts', metavar='SCRIPT', nargs='+',
                         help='List scripts to obfuscated, the first script '
                         'is entry script')
    cparser.add_argument('-s', '--src', metavar='PATH',
                         help='Specify source path if entry script is not '
                         'in the top most path')
    cparser.add_argument('-e', '--entry', metavar='SCRIPT',
                         help=argparse.SUPPRESS)
    cparser.add_argument('--cross-protection', choices=(0, 1),
                         help=argparse.SUPPRESS)
    cparser.add_argument('--plugin', dest='plugins', metavar='NAME',
                         action='append',
                         help='Insert extra code to entry script, '
                         'it could be used multiple times')
    cparser.add_argument('--restrict', type=int, choices=range(5),
                         default=1, help='Set restrict mode')
    cparser.add_argument('--capsule', help=argparse.SUPPRESS)
    cparser.add_argument('--platform', dest='platforms', metavar='NAME',
                         action='append',
                         help='Target platform to run obfuscated scripts, '
                         'use this option multiple times for more platforms')
    cparser.add_argument('--advanced', nargs='?', const=1, type=int,
                         default=0, choices=(0, 1),
                         help='Enable advanced mode')
    cparser.add_argument('--package-runtime', type=int, default=1,
                         choices=(0, 1), help='Package runtime files or not')
    cparser.add_argument('-n', '--no-runtime', action='store_true',
                         help='DO NOT generate runtime files')
    cparser.add_argument('--enable-suffix', action='store_true',
                         help='Make unique runtime files and bootstrap code')
    cparser.set_defaults(func=_obfuscate)

    #
    # Command: license
    #
    cparser = subparsers.add_parser(
        'licenses',
        aliases=['l'],
        epilog=_licenses.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Generate new licenses for obfuscated scripts'
    )
    cparser.add_argument('codes', nargs='+', metavar='CODE',
                         help='Registration code for this license')
    group = cparser.add_argument_group('Bind license to hardware')
    group.add_argument('-e', '--expired', metavar='YYYY-MM-DD',
                       help='Expired date for this license')
    group.add_argument('-d', '--bind-disk', metavar='SN',
                       help='Bind license to serial number of harddisk')
    group.add_argument('-4', '--bind-ipv4', metavar='a.b.c.d',
                       help='Bind license to ipv4 addr')
    # group.add_argument('-6', '--bind-ipv6', metavar='a:b:c:d',
    #                    help='Bind license to ipv6 addr')
    group.add_argument('-m', '--bind-mac', metavar='x:x:x:x',
                       help='Bind license to mac addr')
    group.add_argument('-x', '--bind-data', metavar='DATA', help='Pass extra '
                       'data to license, used to extend license type')
    group.add_argument('--bind-domain', metavar='DOMAIN',
                       help='Bind license to domain name')
    group.add_argument('--bind-file', metavar='filename;target_filename',
                       help=argparse.SUPPRESS)
    cparser.add_argument('-P', '--project', default='', help=argparse.SUPPRESS)
    cparser.add_argument('-C', '--capsule', help=argparse.SUPPRESS)
    cparser.add_argument('-O', '--output', help='Output path, default is '
                         '`licenses` (`stdout` is also supported)')
    cparser.add_argument('--disable-restrict-mode', action='store_true',
                         help='Disable all the restrict modes')
    cparser.add_argument('--enable-period-mode', action='store_true',
                         help='Check license periodly (per hour)')
    cparser.add_argument('--restrict', type=int, choices=(0, 1),
                         default=1, help=argparse.SUPPRESS)

    cparser.set_defaults(func=_licenses)

    #
    # Command: pack
    #
    cparser = subparsers.add_parser(
        'pack',
        aliases=['p'],
        epilog=packer.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Pack obfuscated scripts to one bundle'
    )
    packer.add_arguments(cparser)
    cparser.set_defaults(func=packer.packer)

    #
    # Command: init
    #
    cparser = subparsers.add_parser(
        'init',
        aliases=['i'],
        epilog=_init.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Create a project to manage obfuscated scripts'
    )
    cparser.add_argument('-t', '--type', default='auto',
                         choices=('auto', 'app', 'pkg'))
    cparser.add_argument('-e', '--entry',
                         help='Entry script of this project')
    cparser.add_argument('-s', '--src', default='',
                         help='Project src, base path for matching scripts')
    cparser.add_argument('--capsule', help=argparse.SUPPRESS)
    cparser.add_argument('project', nargs='?', default='', help='Project path')
    cparser.set_defaults(func=_init)

    #
    # Command: config
    #
    cparser = subparsers.add_parser(
        'config',
        aliases=['c'],
        epilog=_config.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Update project settings')
    cparser.add_argument('project', nargs='?', metavar='PATH',
                         default='', help='Project path')
    cparser.add_argument('--name')
    cparser.add_argument('--title')
    cparser.add_argument('--src',
                         help='Project src, base path for matching scripts')
    cparser.add_argument('--output',
                         help='Output path for obfuscated scripts')
    cparser.add_argument('--capsule', help=argparse.SUPPRESS)
    cparser.add_argument('--platform', dest='platforms', metavar='NAME',
                         action='append',
                         help='Target platform to run obfuscated scripts, '
                         'use this option multiple times for more platforms')
    cparser.add_argument('--manifest', metavar='TEMPLATE',
                         help='Filter the project scritps by these manifest '
                         'template commands')
    cparser.add_argument('--entry', metavar='SCRIPT',
                         help='Entry script of this project, sperated by "," '
                         'for multiple entry scripts')
    cparser.add_argument('--is-package', type=int, choices=(0, 1))
    cparser.add_argument('--disable-restrict-mode', type=int, choices=(0, 1),
                         help=argparse.SUPPRESS)
    cparser.add_argument('--restrict', '--restrict-mode', dest='restrict_mode',
                         type=int, choices=range(5),
                         help='Set restrict mode')
    cparser.add_argument('--obf-module-mode', choices=Project.OBF_MODULE_MODE,
                         help=argparse.SUPPRESS)
    cparser.add_argument('--obf-code-mode', choices=Project.OBF_CODE_MODE,
                         help=argparse.SUPPRESS)
    cparser.add_argument('--obf-mod', type=int, choices=(0, 1))
    cparser.add_argument('--obf-code', type=int, choices=(0, 1, 2))
    cparser.add_argument('--wrap-mode', type=int, choices=(0, 1))
    cparser.add_argument('--cross-protection', type=int, choices=(0, 1),
                         help='Insert cross protection code to entry script '
                         'or not')
    cparser.add_argument('--bootstrap', '--bootstrap-code', type=int,
                         dest='bootstrap_code', choices=(0, 1, 2, 3),
                         help='How to insert bootstrap code to entry script')
    cparser.add_argument('--runtime-path', metavar="RPATH",
                         help='The path to search dynamic library in runtime, '
                         'if it is not within the runtime package')
    cparser.add_argument('--plugin', dest='plugins', metavar='NAME',
                         action='append',
                         help='Insert extra code to entry script, '
                         'it could be used multiple times')
    cparser.add_argument('--advanced', '--advanced-mode', dest='advanced_mode',
                         type=int, choices=(0, 1),
                         help='Enable or disable advanced mode')
    cparser.add_argument('--package-runtime', choices=(0, 1), type=int,
                         help='Package runtime files or not')
    cparser.add_argument('--enable-suffix', type=int, choices=(0, 1),
                         help='Make unique runtime files and bootstrap code')
    cparser.add_argument('--with-license', dest='license_file',
                         help='Use this license file other than default')
    # cparser.add_argument('--reset', choices=('all', 'glob', 'exact'),
    #                      help='Initialize project scripts by different way')
    # cparser.add_argument('--exclude', dest="exludes", action="append",
    #                      help='Exclude the path or script from project. '
    #                      'This option could be used multiple times')
    cparser.set_defaults(func=_config)

    #
    # Command: build
    #
    cparser = subparsers.add_parser(
        'build',
        aliases=['b'],
        epilog=_build.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Obfuscate all the scripts in the project')
    cparser.add_argument('project', nargs='?', metavar='PATH', default='',
                         help='Project path, or project configuratioin file')
    cparser.add_argument('-B', '--force', action='store_true',
                         help='Force to obfuscate all scripts, otherwise '
                         'only obfuscate the changed scripts since last build')
    cparser.add_argument('-r', '--only-runtime', action='store_true',
                         help='Generate runtime files only')
    cparser.add_argument('-n', '--no-runtime', action='store_true',
                         help='DO NOT generate runtime files')
    cparser.add_argument('-O', '--output',
                         help='Output path, override project configuration')
    cparser.add_argument('--platform', dest='platforms', metavar='NAME',
                         action='append',
                         help='Target platform to run obfuscated scripts, '
                         'use this option multiple times for more platforms')
    cparser.add_argument('--package-runtime', choices=(0, 1), type=int,
                         help='Package runtime files or not')
    cparser.set_defaults(func=_build)

    #
    # Command: info
    #
    cparser = subparsers.add_parser(
        'info',
        epilog=_info.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Show project information'
    )
    cparser.add_argument('project', nargs='?', metavar='PATH',
                         default='', help='Project path')
    cparser.set_defaults(func=_info)

    #
    # Command: check
    #
    cparser = subparsers.add_parser(
        'check',
        epilog=_check.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Check consistency of project')
    cparser.add_argument('project', nargs='?', metavar='PATH',
                         default='', help='Project path')
    cparser.set_defaults(func=_check)

    #
    # Command: hdinfo
    #
    cparser = subparsers.add_parser(
        'hdinfo',
        epilog=_hdinfo.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Show hardware information'
    )
    cparser.set_defaults(func=_hdinfo)

    #
    # Command: benchmark
    #
    cparser = subparsers.add_parser(
        'benchmark',
        epilog=_benchmark.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Run benchmark test in current machine'
    )
    cparser.add_argument('-m', '--obf-mod', choices=(0, 1),
                         default=1, type=int)
    cparser.add_argument('-c', '--obf-code', choices=(0, 1, 2),
                         default=1, type=int)
    cparser.add_argument('-w', '--wrap-mode', choices=(0, 1),
                         default=1, type=int)
    cparser.add_argument('--debug', action='store_true',
                         help='Do not clean the test scripts'
                              'generated in real time')
    cparser.set_defaults(func=_benchmark)

    #
    # Command: capsule
    #
    cparser = subparsers.add_parser(
        'capsule',
        epilog=_capsule.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        add_help=False)
    cparser.add_argument('-f', '--force', action='store_true',
                         help='Force update public capsule even if it exists')
    cparser.add_argument('path', nargs='?', default=os.path.expanduser('~'),
                         help='Path to save capsule, default is home path')
    cparser.set_defaults(func=_capsule)

    #
    # Command: register
    #
    cparser = subparsers.add_parser(
        'register',
        epilog=_register.__doc__ + purchase_info,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Make registration keyfile work')
    cparser.add_argument('-n', '--legency', action='store_true',
                         help='Store `license.lic` in the traditional way')
    cparser.add_argument('filename', nargs='?', metavar='KEYFILE',
                         help='Filename of registration keyfile')
    cparser.set_defaults(func=_register)

    #
    # Command: download
    #
    cparser = subparsers.add_parser(
        'download',
        epilog=_download.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Download platform-dependent dynamic libraries')
    cparser.add_argument('-O', '--output', metavar='PATH',
                         help='Save downloaded library to this path, default '
                         'is `~/.pyarmor/platforms`')
    cparser.add_argument('--url', help=argparse.SUPPRESS)
    group = cparser.add_mutually_exclusive_group()
    group.add_argument('--help-platform', nargs='?', const='',
                       metavar='FILTER',
                       help='Display all available platform names')
    group.add_argument('-L', '--list', nargs='?', const='',
                       dest='pattern', metavar='FILTER',
                       help='List available dynamic libraries in details')
    group.add_argument('-u', '--update', nargs='?', const='*', metavar='NAME',
                       help='Update all the downloaded dynamic libraries')
    group.add_argument('platname', nargs='?', metavar='NAME',
                       help='Download dynamic library for this platform')
    cparser.set_defaults(func=_download)

    #
    # Command: runtime
    #
    cparser = subparsers.add_parser(
        'runtime',
        epilog=_runtime.__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Generate runtime package separately')
    cparser.add_argument('-O', '--output', metavar='PATH', default='dist',
                         help='Output path, default is "%(default)s"')
    cparser.add_argument('-n', '--no-package', action='store_true',
                         help='Generate runtime files without package')
    cparser.add_argument('-i', '--inside', action='store_true',
                         help='Generate bootstrap script which is used '
                         'inside one package')
    cparser.add_argument('-L', '--with-license', metavar='FILE',
                         help='Replace default license with this file')
    cparser.add_argument('--platform', dest='platforms', metavar='NAME',
                         action='append',
                         help='Generate runtime package for this platform, '
                         'use this option multiple times for more platforms')
    cparser.add_argument('--enable-suffix', action='store_true',
                         help='Make unique runtime files and bootstrap code')
    cparser.add_argument('pkgname', nargs='?', default='pytransform',
                         help=argparse.SUPPRESS)
    cparser.set_defaults(func=_runtime)

    return parser