Esempio n. 1
0
def pull(remote: git.Remote):
    """
    Performs a Git pull from a given remote repository.

    :param remote:  git.Remote object.
    :return:
    """
    log.info("Pulling data from remote '{}'...".format(remote))
    try:
        remote.pull()
    except git.exc.GitCommandError as git_exc:
        log.exception("Failed to pull from remote '{}'!".format(remote), exc_info=git_exc)
        sys.stderr.write("Failed to pull from remote '{}', "
                         "check that git host is online, then restart or perform a manual pull!".format(remote))
Esempio n. 2
0
def checkout_branch(repo, branch_name, no_pull=False):
    """Checkout a branch and optionally pull updates.

    :param repo: Repo object
    :param branch_name: Name of the branch to checkout
    :param no_pull: (Default: False) If True, don't pull changes to branch

    :return: Head object for the checked out branch
    """
    base_head = Head(repo, f'refs/heads/{branch_name}')
    if repo.active_branch != base_head:
        print(f'Checking out {branch_name}.')
        base_head.checkout()
    if not no_pull and base_head.tracking_branch():
        print(f'Pulling updates to {branch_name}...')
        remote_name = base_head.tracking_branch().remote_name
        remote = Remote(repo, remote_name)
        base_commit = base_head.commit
        for fetch_info in remote.pull():
            if fetch_info.ref == base_head.tracking_branch():
                if fetch_info.commit != base_commit:
                    print(
                        f'Updated {branch_name} to {fetch_info.commit.hexsha}')
                else:
                    print(f'{branch_name} already up to date.')
        print('')
    return base_head
Esempio n. 3
0
 def _pull(self, origin: git.Remote):
     if self.git_enabled:
         if self.verbose:
             print('Pulling dot file repository')
         origin.pull()
Esempio n. 4
0
def main():
    """Entrypoint to 'gitsync' command-line tool
    
    """
    parser = argparse.ArgumentParser(
        description='File-sync integrated with Git system solution tool')
    parser.add_argument('-d',
                        '--debug',
                        action='store_true',
                        default=False,
                        help='show more message for debugging')
    parser.add_argument(
        '--config_file',
        help=
        'Specify the location of the settings (Default value: settings.json)',
        type=str,
        default=os.path.join(os.getcwd(), 'settings.json'))
    parser.add_argument('--init',
                        help='Create a template configuration file',
                        action='store_true',
                        default=False)
    parser.add_argument('--version',
                        help='Print the GitSync version number',
                        action='version',
                        version=__version__)

    # Read a set of arguments
    args = parser.parse_args()
    DEBUG = args.debug
    CONFIG_FILE = args.config_file
    INIT = args.init

    # Set Logging Level
    if DEBUG:
        for handler in logging.root.handlers[:]:
            logging.root.removeHandler(handler)
        logging.basicConfig(level=logging.DEBUG, format=FORMAT)

    logger.debug('Config file: {0}'.format(CONFIG_FILE))

    if INIT:
        logger.info('Generate a template setting.json')
        with open('settings_default.json', 'w') as f:
            f.writelines(json.dumps(DEFAULT_SETTING, indent=4))
        sys.exit()

    # Load config
    try:
        logger.debug('Load config...')
        config = load_config(CONFIG_FILE)
        repo_dir = config['repo_dir']
        files_mapping = config['files']
        dirs_mapping = config['dirs']
        ignore_files = config['ignore']['patterns']
        ignore_files.extend(IGNORE_PATTERNS)
        ignore_files = sorted(list(set(ignore_files)))
    except Exception as error:
        logger.error('Can\'t load config: {0}'.format(error))
        sys.exit(1)

    # Read and check repo has been initialized
    logger.debug('Trying to read repo...')
    try:
        repo = Repo(repo_dir)
        remote = Remote(repo, 'origin')
        if not remote.exists():
            logger.error(
                'Can\'t find \'origin\' remote url. Please set a \'origin\' remote and upstream branch at first to proceed!'
            )
            sys.exit(1)
        logger.debug('Repo has been loaded successfully')
        logger.info('Pulling from repo...')
        remote.pull()
    except InvalidGitRepositoryError as error:
        logger.error('Invalid repo. Please check it again!')
        sys.exit(1)
    except NoSuchPathError as error:
        logger.error(
            'No directory \'.git\' found. Did you initialize git project?!')
        sys.exit(1)

    if repo.bare:
        logger.error('Repo can\'t be a bare!')
        sys.exit(1)

    # initialize runtime files/variables
    init_files(repo_dir, ignore_files)
    changed = False
    logger.info('Repo Initialization completed')

    logger.debug('Performing prechecks...')
    try:
        precheck(files_mapping.keys(), dirs_mapping.keys())
    except Exception as error:
        logger.error('Prechecks failed!')
        logger.error(error)
        sys.exit(1)

    logger.debug('Perform cleanup task on repo...')
    clean_up_repo(files_mapping.values(),
                  dirs_mapping.values(),
                  repo_dir,
                  ignore=ignore_files)

    logger.debug('Proceed to check file changes')
    logger.debug('Detect if the sync list changes...')
    prev_config = NO_LAST_SYNC_STATE
    if check_last_sync(repo_dir):
        logger.debug('Last sync record found!')
        prev_config = load_last_sync(repo_dir)

    # Check whether folder states are identical
    logger.info('Check files whether if updated')
    src_files_to_be_copied, src_dirs_to_be_copied, dst_files_to_be_deleted, dst_dirs_to_be_deleted = check_sync_state(
        prev_config, config, repo_dir)
    logger.debug(
        'Sync state: \n\t\tFiles be copied {0}\n\t\tDirs be copied {1}\n\t\tFiles be deleted {2}\n\t\tDirs be deleted {3}'
        .format(src_files_to_be_copied, src_dirs_to_be_copied,
                dst_files_to_be_deleted, dst_dirs_to_be_deleted))

    # Start to perform sync task (overwrite dst-file / delete dst-file / copy entire src-folder(src-file) to dst-folder(dst-file))
    change_indicator = 0
    if (dst_files_to_be_deleted):
        for file_path in dst_files_to_be_deleted:
            try:
                logger.debug('Deleting file {0}'.format(file_path))
                delete_file(file_path)
                logger.debug(' ... Successfully')
            except Exception as error:
                logger.debug(' ... Failed')
                raise error

        logger.debug('Files deletion finished')
        change_indicator += 1

    if (dst_dirs_to_be_deleted):
        for dir_path in dst_dirs_to_be_deleted:
            try:
                logger.debug('Deleting directory {0}'.format(dir_path))
                delete_dir(dir_path)
                logger.debug(' ... Successfully')
            except Exception as error:
                logger.debug(' ... Failed')
                raise error
        logger.debug('Dirs deletion finished')
        change_indicator += 1

    if (src_files_to_be_copied):
        for src_path, dst_path in src_files_to_be_copied.items():
            try:
                logger.debug('Copying file {0} to {1}'.format(
                    src_path, dst_path))
                copy_file(src_path, dst_path)
                logger.debug(' ... Successfully')
            except Exception as error:
                logger.debug(' ... Failed')
                raise error
        logger.debug('Files addition finished')
        change_indicator += 1

    if (src_dirs_to_be_copied):
        for src_path, dst_path in src_dirs_to_be_copied.items():
            try:
                logger.debug('Copying directory {0} to {1}'.format(
                    src_path, dst_path))
                copy_dir(src_path, dst_path, ignore=ignore_files)
                logger.debug(' ... Successfully')
            except Exception as error:
                logger.debug(' ... Failed')
                raise error
        logger.debug('Dirs addition finished')
        change_indicator += 1

    if change_indicator == 0:
        logger.info('All is up to date')
        sys.exit(0)

    logger.debug('Staging files...')
    logger.debug('Reset current staging')
    repo.index.reset()

    logger.info('Stage modified files into repo...')
    repo.git.add(A=True)

    logger.info('Commit to repo...')
    repo.index.commit('[(auto-git) leave it here for later editing]')

    logger.info('Push to remote origin server...')
    remote.push()

    logger.debug('Saving current sync state...')
    try:
        save_current_sync(repo_dir, config)
    except Exception as error:
        logger.error('Failed to save current sync state! {0}'.format(error))
        sys.exit(1)
    logger.info('Finished')