def git_ignore(root, patterns):
    classified_patterns = []
    with cd(root):
        for pattern in patterns:
            if pattern:
                if '/' in pattern[:-1]:
                    ignored_paths = (Pattern('path', match)
                                     for match in glob.glob(pattern))
                    classified_patterns.extend(ignored_paths)
                else:
                    classified_patterns.append(Pattern('file', pattern))

    def git_ignorer(src, names):
        relative_src = src[len(root):].lstrip(r"""\/""")
        ignored = []
        for name in names:
            for pattern in classified_patterns:
                if pattern.type == 'path':
                    if path.join(relative_src,
                                 name) == os.path.normpath(pattern.value):
                        ignored.append(name)
                elif pattern.type == 'file':
                    ignore_name = pattern.value
                    if pattern.value[-1] in ('/', '\\'):
                        if path.isdir(path.join(src, name)):
                            ignore_name = ignore_name[:-1]

                    if fnmatch.fnmatch(name, ignore_name):
                        ignored.append(name)

        return set(ignored)

    return git_ignorer
Example #2
0
def git_ignore(root, patterns):
	classified_patterns = []
	with cd(root):
		for pattern in patterns:
			if pattern:
				if '/' in pattern[:-1]:
					ignored_paths = (Pattern('path', match) for match in glob.glob(pattern))
					classified_patterns.extend(ignored_paths)
				else:
					classified_patterns.append(Pattern('file', pattern))

	def git_ignorer(src, names):
		relative_src = src[len(root):].lstrip(r"""\/""")
		ignored = []
		for name in names:
			for pattern in classified_patterns:
				if pattern.type == 'path':
					if path.join(relative_src, name) == os.path.normpath(pattern.value):
						ignored.append(name)
				elif pattern.type == 'file':
					ignore_name = pattern.value
					if pattern.value[-1] in ('/', '\\'):
						if path.isdir(path.join(src, name)):
							ignore_name = ignore_name[:-1]

					if fnmatch.fnmatch(name, ignore_name):
						ignored.append(name)

		return set(ignored)

	return git_ignorer
Example #3
0
def _serve(build, target, address, port):
	LOG.info("Initializing Forge Live...");

	_update_path_for_node(build)
	_setup_livereload(build, target)

	LOG.info("Serving live updates for '%s' on: http://%s:%s" % (target, address, port));

	# call grunt serve
	if sys.platform.startswith("win"):
		grunt = path.join("node_modules", ".bin", "grunt.cmd")
	else:
		grunt = path.join("node_modules", ".bin", "grunt")

	grunt_serve_cmd = [grunt, "serve", 
					   "--address", address,
					   "--port", "{port}".format(port=port),
					   "--target", target,
					   "--no-color"]

	def could_not_start_grunt(line):
		return line.startswith("TODO error condition")

	with cd(path.join("development", "live")):
		process_group = utils.ProcessGroup()
		process_group.spawn(
			grunt_serve_cmd,
			fail_if=could_not_start_grunt,
			command_log_level=logging.DEBUG
		)
Example #4
0
def _setup_livereload(build, target):
	'''setup livereload service'''	

	template = lib.expand_relative_path(build, path.join('.template', 'lib', 'live'))
	live = lib.expand_relative_path(build, path.join('development', 'live'))

	if not path.isdir(live):
		os.mkdir(live)

	with cd(live):
		shutil.copyfile(path.join(template, "package.json"), "package.json")
		shutil.copyfile(path.join(template, "Gruntfile.js"), "Gruntfile.js")
		_npm(build, "install")
Example #5
0
def run_web(build):
    """Run an instance of Node locally"""
    # TODO: port should be a parameter/configuration
    port = 3000
    _update_path_for_node(build)

    def show_local_server():
        LOG.info("Attempting to open browser at http://localhost:%d/" % port)
        _open_url("http://localhost:%d/" % port)

    with cd(path.join("development", "web")):
        timer = None
        try:
            # TODO: annoyingly difficult to kill npm processes on windows - npm.cmd actually
            # launches an instance of node as a subprocess which is the real thing you need to kill!
            # might be possible to kill npm.cmd in a nicer way, e.g. sending a CTRL_C event, needs
            # a bit of experimentation
            _npm(build, "install")

            attempts = 0
            while not _port_available(port):
                LOG.info('Port still in use, attempting to send a kill signal')
                #TODO: appropriate timeout and handling
                requests.post('http://localhost:%d/_forge/kill/' % port)

                time.sleep(1)

                attempts += 1
                if attempts > 5:
                    raise WebError(
                        "Port %d seems to be in use, you should specify a different port to use"
                        % port)

            timer = threading.Timer(3, show_local_server).start()
            _node(build,
                  "./web.js",
                  command_log_level=logging.INFO,
                  check_for_interrupt=True,
                  env=dict(os.environ, PORT=str(port), FORGE_DEBUG='1'))

        finally:
            if timer:
                timer.cancel()
Example #6
0
def run_web(build):
	"""Run an instance of Node locally"""
	# TODO: port should be a parameter/configuration
	port = 3000
	_update_path_for_node(build)

	def show_local_server():
		LOG.info("Attempting to open browser at http://localhost:%d/" % port)
		_open_url("http://localhost:%d/" % port)

	with cd(path.join("development", "web")):
		timer = None
		try:
			# TODO: annoyingly difficult to kill npm processes on windows - npm.cmd actually
			# launches an instance of node as a subprocess which is the real thing you need to kill!
			# might be possible to kill npm.cmd in a nicer way, e.g. sending a CTRL_C event, needs
			# a bit of experimentation
			_npm(build, "install")

			attempts = 0
			while not _port_available(port):
				LOG.info('Port still in use, attempting to send a kill signal')
				#TODO: appropriate timeout and handling
				requests.post('http://localhost:%d/_forge/kill/' % port)

				time.sleep(1)

				attempts += 1
				if attempts > 5:
					raise WebError("Port %d seems to be in use, you should specify a different port to use" % port)

			timer = threading.Timer(3, show_local_server).start()
			_node(build, "./web.js", command_log_level=logging.INFO,
					check_for_interrupt=True,
					env=dict(os.environ, PORT=str(port), FORGE_DEBUG='1'))

		finally:
			if timer:
				timer.cancel()
Example #7
0
def package_web(build):
	interactive = build.tool_config.get('general.interactive', True)
	development = lib.expand_relative_path(build, 'development/web')
	output = lib.expand_relative_path(build, 'release/web/heroku')

	# deploy to Heroku
	with cd(development):
		api_key = _get_heroku_api_key(build)
		chosen_app = _get_app_to_push_to(build, api_key)

		if not path.isdir(output):
			os.makedirs(output)

		with cd(output):
			if not path.isdir('.git'):
				LOG.debug('Creating git repo')
				_git('init')

				LOG.debug('Create dummy first commit')
				with open('.forge.txt', 'w') as forge_file:
					forge_file.write('')
				_git('add', '.')
				_git('commit', '-am', 'first commit')

		# remove all previous files/folders except for .git!
		with cd(output):
			for f in os.listdir('.'):
				if not f == '.git':
					if path.isfile(f):
						os.remove(f)

					elif path.isdir(f):
						shutil.rmtree(f)

		# copy code from development to release!
		with cd(development):
			for f in os.listdir('.'):
				if path.isfile(f):
					shutil.copy2(f, output)
				elif path.isdir(f) and path.basename(f) != '.git':
					shutil.copytree(f, path.join(output, f), ignore=shutil.ignore_patterns('.git'))

		with cd(output):
			# setup with the specified remote
			LOG.debug('Setting up git remote for %s' % chosen_app)

			# remove any previous remote
			try:
				_git('remote', 'rm', 'heroku')
			except WebError:
				pass

			_git('remote', 'add', 'heroku', '[email protected]:%s.git' % chosen_app)

			# commit
			_git('add', '.')
			diff = _git('diff', 'HEAD')
			if not diff.strip():
				# not interactive basically means we're using the trigger toolkit, where 'forge build'
				# doesn't really make sense
				if interactive:
					LOG.warning("No app changes detected: did you forget to forge build?")
				else:
					LOG.warning("No app changes detected, pushing to heroku anyway")
			else:
				_git('commit', '-am', 'forge package web')

			# push
			LOG.info('Deploying to %s.herokuapp.com' % chosen_app)

			# TODO: when running a packaged up toolkit there is no commandline... need to make sure
			# we can use the ssh key earlier somehow and ask for passphrase if not
			# also provide docs on how to use ssh-agent/pageant
			if not interactive:
				LOG.warning('If the packaging process hangs here, you need to set up ssh-agent or Pageant')

			# TODO: show our own one line progress bar when running non-verbosely
			push_output = _git('push', 'heroku', '--all', '--force', command_log_level=logging.INFO)

			if push_output.startswith('Everything up-to-date'):
				remote_output = _git('remote', '-v')
				remote_pattern = re.compile(r'[email protected]:(.*?).git \(fetch\)')

				remote_match = remote_pattern.search(remote_output)
				if remote_match:
					app_url = 'http://%s.herokuapp.com' % remote_match.group(1)
					_open_url(app_url)
					LOG.info('Deployed at %s' % app_url)

			else:
				deploy_pattern = re.compile(r'(http://[^ ]+) deployed to Heroku')
				deploy_match = deploy_pattern.search(push_output)
				if deploy_match:
					_open_url(deploy_match.group(1))
					LOG.info('Deployed at %s' % deploy_match.group(1))
Example #8
0
def package_web(build):
    interactive = build.tool_config.get('general.interactive', True)
    development = lib.expand_relative_path(build, 'development/web')
    output = lib.expand_relative_path(build, 'release/web/heroku')

    # deploy to Heroku
    with cd(development):
        api_key = _get_heroku_api_key(build)
        chosen_app = _get_app_to_push_to(build, api_key)

        if not path.isdir(output):
            os.makedirs(output)

        with cd(output):
            if not path.isdir('.git'):
                LOG.debug('Creating git repo')
                _git('init')

                LOG.debug('Create dummy first commit')
                with open('.forge.txt', 'w') as forge_file:
                    forge_file.write('')
                _git('add', '.')
                _git('commit', '-am', 'first commit')

        # remove all previous files/folders except for .git!
        with cd(output):
            for f in os.listdir('.'):
                if not f == '.git':
                    if path.isfile(f):
                        os.remove(f)

                    elif path.isdir(f):
                        shutil.rmtree(f)

        # copy code from development to release!
        with cd(development):
            for f in os.listdir('.'):
                if path.isfile(f):
                    shutil.copy2(f, output)
                elif path.isdir(f) and path.basename(f) != '.git':
                    shutil.copytree(f,
                                    path.join(output, f),
                                    ignore=shutil.ignore_patterns('.git'))

        with cd(output):
            # setup with the specified remote
            LOG.debug('Setting up git remote for %s' % chosen_app)

            # remove any previous remote
            try:
                _git('remote', 'rm', 'heroku')
            except WebError:
                pass

            _git('remote', 'add', 'heroku',
                 '[email protected]:%s.git' % chosen_app)

            # commit
            _git('add', '.')
            diff = _git('diff', 'HEAD')
            if not diff.strip():
                # not interactive basically means we're using the trigger toolkit, where 'forge build'
                # doesn't really make sense
                if interactive:
                    LOG.warning(
                        "No app changes detected: did you forget to forge build?"
                    )
                else:
                    LOG.warning(
                        "No app changes detected, pushing to heroku anyway")
            else:
                _git('commit', '-am', 'forge package web')

            # push
            LOG.info('Deploying to %s.herokuapp.com' % chosen_app)

            # TODO: when running a packaged up toolkit there is no commandline... need to make sure
            # we can use the ssh key earlier somehow and ask for passphrase if not
            # also provide docs on how to use ssh-agent/pageant
            if not interactive:
                LOG.warning(
                    'If the packaging process hangs here, you need to set up ssh-agent or Pageant'
                )

            # TODO: show our own one line progress bar when running non-verbosely
            push_output = _git('push',
                               'heroku',
                               '--all',
                               '--force',
                               command_log_level=logging.INFO)

            if push_output.startswith('Everything up-to-date'):
                remote_output = _git('remote', '-v')
                remote_pattern = re.compile(
                    r'[email protected]:(.*?).git \(fetch\)')

                remote_match = remote_pattern.search(remote_output)
                if remote_match:
                    app_url = 'http://%s.herokuapp.com' % remote_match.group(1)
                    _open_url(app_url)
                    LOG.info('Deployed at %s' % app_url)

            else:
                deploy_pattern = re.compile(
                    r'(http://[^ ]+) deployed to Heroku')
                deploy_match = deploy_pattern.search(push_output)
                if deploy_match:
                    _open_url(deploy_match.group(1))
                    LOG.info('Deployed at %s' % deploy_match.group(1))