Esempio n. 1
0
    def _deduce_app_name(self):
        """
        If an app name is not provided, try and figure one out.
        """

        # Check and see if we can use the destination as a valid
        #   name.
        use_dest = True
        if file_exists(self.dest) and os.path.isdir(self.dest):
            use_dest = False
        elif file_exists(self.dest) and os.path.isfile(self.dest):
            # Confirm overwrite
            use_dest = True

        if use_dest:
            app_name = os.path.basename(self.dest)
            self.dest = os.path.dirname(self.dest)
        else:
            if self.src_directory.endswith('/'):
                tmp_src_directory = self.src_directory[:-1]
            else:
                tmp_src_directory = self.src_directory

            app_name = '{0}.pyz'.format(os.path.basename(tmp_src_directory))

        if not app_name:
            raise ZapperError('Unable to deduce app name!')

        return app_name
Esempio n. 2
0
def _read_build_file(build_file_path):
    """
    Read the 'build' file.

    Args:
        build_file_path (str):      The path to the build file

    Returns:
        dict containing contents of 'build' file.

    Raises:
        IOError if the provided build file doesn't exist.
        ValueError if build file does not contain 'zapper' key.
    """
    # Check if we're given a file handle. If we are, just read it.
    #   otherwise, do all our normal file operations.
    if isinstance(build_file_path, file):
        build_data = yaml.load(build_file_path.read())

    else:
        if not file_exists(build_file_path):
            return {}

        # Read a build file located in the source path.
        with open(build_file_path, 'r') as f:
            build_data = yaml.load(f.read())

    # We require that the build file have a zapper "root" key,
    #   so we'll raise a ValueError if it does not.
    if 'zapper' not in build_data:
        raise ValueError('"{0}" does not contain a "zapper" key!'.format(build_file_path))

    return build_data['zapper']
Esempio n. 3
0
def _find_build_file(src_path):
    """
    Search for a 'build' file.

    Args:
        src_path (str):     The path to the search.

    Returns:
        str containing full path to a build file.

    Raises:
        ValueError if we can't find a build file.
    """
    # Possible names for the build file. 'build' and 'build.yml'
    #   seemed sensible enough.
    possible_build_file_names = ['build', 'build.yml', 'build.yaml']

    # Look for a file named either 'build' or 'build.yml'
    build_file = None
    for build_file_name in possible_build_file_names:
        build_file_path = os.path.join(src_path, build_file_name)
        if file_exists(build_file_path):
            build_file = build_file_path
            break

    # If we get here, and don't have a build file, just return None.
    return build_file
Esempio n. 4
0
    def _clean(self):
        """
        Clean up after myself.
        """
        self._debug('Cleaning up')

        # Loop through all files we've created, and attempt
        #   to remove them.
        for fpath in self.files_created:
            if not file_exists(fpath):
                continue

            self._debug('Removing "{0}"'.format(fpath))
            if os.path.isdir(fpath):
                rmtree(fpath)
            else:
                os.remove(fpath)
Esempio n. 5
0
def _parse_args():
    """
    Parse Command Line Args.

    Returns:
        argparse object.

    Raises:
        ValueError if 'src' path is invalid.
    """
    # Set up our argument parser.
    parser = argparse.ArgumentParser(
        description='A tool to build python zipapps.',
        usage='%(prog)s SRC_PATH [DEST_PATH]',
        epilog='NOTE: Any options specified on the command line will override ALL defined builds.'
               'This means if you specify "app_name" on the command line, and you have multiple '
               'builds specied in the "build_file", that "app_name" will be applied to all resulting '
               'artifacts.'
    )

    parser.add_argument('src_path',
                        nargs=1,
                        type=str,
                        help='Path to the app to build.')
    parser.add_argument('dest_path',
                        nargs='?',
                        type=str,
                        help='The desired destination.')
    parser.add_argument('-b', '--build-file',
                        type=argparse.FileType(),
                        help='Path to a build file.')
    parser.add_argument('-n', '--name',
                        type=str,
                        help='Specify a name for the application. By default basename is used.')
    parser.add_argument('-e', '--entry-point',
                        type=str,
                        help='The entry point for the application.')
    parser.add_argument('-r', '--requirements',
                        type=str,
                        help='Comma separated .ist of requirements. '
                             'Prepend with an "@" sign to specify a requirements file')
    parser.add_argument('--ignore',
                        type=str,
                        help='Comma separated list of files/directories to ignore.')
    parser.add_argument('--leave-pyc',
                        action='store_true',
                        default=False,
                        help='Toggles NOT cleaning out any pyc files.')
    parser.add_argument('--python-shebang',
                        type=str,
                        help='Specify a nonstandard python-shebang.')
    parser.add_argument('-v', '--verbose',
                        action='store_true',
                        default=False,
                        help='Toggle verbosity.')

    args = parser.parse_args()

    # Ensure the provided Source Path exists, and raise a
    #   ValueError if it does not.
    args.src_path = args.src_path[0]
    if not file_exists(args.src_path):
        raise ValueError('"{0}" does not exist or is not readable!'
                         .format(args.src_path))

    return args
Esempio n. 6
0
    def _install_requirements(self):
        """
        Install specified dependencies to a 'vendor' directory.

        If requirements are defined in the build file, install those to
            a 'vendor' directory. If they are not defined, read the
            'requirements.txt' file (if it exists) and install those to
            a 'vendor' directory.

        Raises:
            OSError if Pip is not installed.
        """

        # On windows, pip is 'pip.exe', but everywhere else its pip.
        if os.name == 'posix':
            pip_name = 'pip'
        else:
            pip_name = 'pip.exe'

        # Test if Pip is installed and bomb if it's not.
        pip_cmd = which(pip_name)
        if not pip_cmd:
            raise ZapperError('Required program "pip" not installed!')

        # Check if our vendor path exists, and if it doesn't,
        #   create it. This way if a project already has one,
        #   I don't step on too many toes.
        self._debug('Installing Dependencies.')
        if not file_exists(self.vendor_path):
            self._debug('Creating "{0}"'.format(self.vendor_path))
            os.makedirs(self.vendor_path)
            self.files_created.append(self.vendor_path)

        # Loop through provided requirements and install
        #   run 'pip install'
        if self.requirements:
            self._debug('Requrements List provided.')
            for requirement in self.requirements:
                cmd = [
                    pip_cmd,
                    'install',
                    '{0}'.format(requirement),
                    '--target={0}'.format(self.vendor_path),
                ]

                self._debug('Installing "{0}"" with command "{1}"'
                            .format(requirement, self.vendor_path))

                try:
                    output = subprocess.check_output(cmd)
                except subprocess.CalledProcessError as e:
                    raise ZapperError(
                        'Failed while installing dependencies! Error: "{0}"'
                        .format(e))
                self._debug('{0}'.format(output))

        # If a requirements.txt file is provided, feed it to 'pip'
        #   and install everything to the vendor directory.
        if self.requirements_txt:
            if not file_exists(self.requirements_txt):
                self._debug('"requirements.txt" not found at: "{0}"'
                            .format(self.requirements_txt))
                return

            cmd = [
                'pip',
                'install',
                '-r',
                '{0}'.format(self.requirements_txt),
                '--target={0}'.format(self.vendor_path),
            ]

            self._debug('Running command: "{0}"'.format(cmd))

            try:
                output = subprocess.check_output(cmd)
            except subprocess.CalledProcessError as e:
                raise ZapperError(
                    'Failed while installing dependencies! Error: "{0}"'
                    .format(e))
            self._debug('{0}'.format(output))