def upload(self, local_path, artifact=None, force=False, print_only=False):
        """
        Upload local artifact and update index

        :param local_path: source file path to upload
        :param artifact: artifact object to upload
                         If artifact is None, generate artifact object from local_path.
                         Revision will be updated.
        :param force:
        :param print_only:
        :return: None
        """
        art = deepcopy(artifact)
        if not artifact:
            art = Artifact.from_path(self.group_id, local_path)

        bi = art.basic_info
        fi = art.file_info

        # check if the artifact is already in index
        revisions = self._get_artifacts(bi.artifact_id, bi.version,
                                        bi.packaging)
        xs = [
            x for x in revisions
            if (x.file_info.size, x.file_info.md5) == (fi.size, fi.md5)
        ]
        if xs and not force:
            logging.warn('Already uploaded as:\n%s' % xs[0])
            return

        # increment revision
        latest = self._get_latest_artifact(bi.artifact_id, bi.version,
                                           bi.packaging)
        current_revision = latest[0].basic_info.revision if latest else 0
        bi.revision = current_revision + 1

        # upload file
        if print_only:
            logging.info('Would upload artifact: \n\n%s\n' % art)
            return

        logging.info('Uploading artifact: \n%s\n' % art)
        self.driver.upload(local_path, bi.s3_path(), fi.md5)

        # update index
        self.artifacts[bi.artifact_id].append(art)