Пример #1
0
def create_dam_path(local_path, local_import_root, dam_import_root):
    """ Returns <ok>, <path> """
    ret = local_path.replace(local_import_root, dam_import_root)
    log("=== 1 {}".format(ret))
    ret = ret.replace("\\", "/")
    log("=== 2 {}".format(ret))
    return ret
Пример #2
0
def _post_file(server, filepath, dst_path, dry_run):
    """ POST single file to DAM
        curl -v -u admin:admin -X POST -i -F "file=@\"$FILENAME\"" $HOST$dampath.createasset.html &> $tempfile
    """
    assert os.path.isfile(filepath)

    if dry_run:
        return OK

    filename = os.path.basename(filepath)
    f = open(filepath, 'rb')
    mime, enc = mimetypes.guess_type(filepath)
    log("Uploading {} as {}, {}".format(f, mime, enc))
    form_data = dict(
        file=(filename, f, mime, dict()),
        fileName=filename
    )

    url = server.url("{path}.createasset.html".format(path=dst_path, filename=os.path.basename(filepath)))
    log("POSTing to {}".format(url))
    resp = requests.post(url, auth=server.auth, files=form_data)
    if not _ok(resp.status_code):
        error("Failed to upload file {}\n{}".format(filepath, resp.content))
        return SERVER_ERROR
    return OK
Пример #3
0
def clear_cache(server, options):
    host_url = urlparse(server.host)

    headers = {
        'Host': host_url.hostname,
        'CQ-Action': 'DELETE',
        'CQ-Handle': '/',
        'CQ-Path': '/'
    }

    host = server.dispatcher if server.dispatcher is not None else server.host
    url = '{host}{path}'.format(host=host, path='/dispatcher/invalidate.cache')
    log("Clearing cache with request to {}".format(url))
    response = requests.get(url, auth=server.auth, headers=headers)
    if response.status_code != 200:
        sys.stderr.write("error: " + str(response.status_code) + "\n")
        return SERVER_ERROR
    if "<H1>OK</H1>" not in response.content:
        sys.stderr.write("error: Failed to validate response '{}'\n".format(
            response.content.strip()))
        return SERVER_ERROR

    if options.raw:
        sys.stdout.write(response.content + "\n")
    else:
        sys.stdout.write("OK\n")
Пример #4
0
def clear_cache(server, options):
    host_url = urlparse(server.host)

    headers = {
        'Host': host_url.hostname,
        'CQ-Action': 'DELETE',
        'CQ-Handle': '/',
        'CQ-Path': '/'
    }

    host = server.dispatcher if server.dispatcher is not None else server.host
    url = '{host}{path}'.format(host=host, path='/dispatcher/invalidate.cache')
    log("Clearing cache with request to {}".format(url))
    response = requests.get(url, auth=server.auth, headers=headers)
    if response.status_code != 200:
        sys.stderr.write("error: " + str(response.status_code) + "\n")
        return SERVER_ERROR
    if "<H1>OK</H1>" not in response.content:
        sys.stderr.write("error: Failed to validate response '{}'\n".format(response.content.strip()))
        return SERVER_ERROR

    if options.raw:
        sys.stdout.write(response.content + "\n")
    else:
        sys.stdout.write("OK\n")
Пример #5
0
    def import_file(self, local_import_root, filepath):
        """ Import single file """
        assert os.path.isfile(filepath)

        dam_path = get_dam_path(filepath, local_import_root,
                                self.destination_root)

        log("Uplading {} to {}".format(filepath, dam_path))

        if dam_path not in self.created_paths:
            self.created_paths.add(dam_path)
            if not self.dry_run:
                self.api.create_folder(dam_path)
        else:
            log("Skipping creating dam path {}".format(dam_path))

        status = OK
        if not self.dry_run:
            status = self.api.create_asset(filepath, dam_path)

        if status == OK:
            sys.stdout.write("{local} -> {dam}\n".format(local=filepath,
                                                         dam=dam_path))
            sys.stdout.flush()
        return status
Пример #6
0
    def _list_assets(self, path):
        """ List assets under path
         
            :return (<status>, <list>)
            <status>: <OK|USER_ERROR|SERVER_ERROR>
            <list> [{name: <name>, title: <title>}...]
        """

        log("Fetching asset list for {}".format(path))
        req_path = "{root}{path}.json".format(root=API_ROOT, path=path)
        url = self.server.url(req_path)

        status, data = self._fetch_json(url)
        if status != OK:
            return SERVER_ERROR, None

        _add_path(data, path)

        next_url = _get_next_url(data)
        while next_url is not None:
            status, next_data = self._fetch_json(next_url)
            if status != OK:
                error("Failed to fetch next listing {}".format(next_url))
                next_url = None
            else:
                _add_path(next_data, path)
                data['entities'].extend(next_data['entities'])
                next_url = _get_next_url(next_data)
        return OK, data
Пример #7
0
 def __init__(self, server, path, force_root=None):
     if force_root is not None:
         self.lock_dir = force_root
     else:
         self.lock_dir = os.path.join(ROOT_IMPORT_DIR,
                                      self._hash_job(server, path))
     log("Cache dir is {}".format(self.lock_dir))
Пример #8
0
    def import_file(self, server, options, import_root, filepath):
        """ Import single file """
        assert os.path.isfile(filepath)

        lock_file = self._lock_file(filepath)
        if os.path.exists(lock_file):
            sys.stdout.write("{i}/{n} Skipping {path}\n".format(i=self.current_file, n=self.total_files, path=filepath))
            return OK

        local_dir = os.path.dirname(filepath)

        dest_dir = options.destination_root
        if dest_dir is None:
            dest_dir = os.path.join('/content/dam', os.path.basename(import_root))

        dam_path = local_dir.replace(import_root, dest_dir)
        log("Uplading {} to {}".format(filepath, dam_path))

        if dam_path not in self.created_paths:
            status = _create_dir(server, dam_path, options.dry_run)
            if status != OK:
                return status
            self.created_paths.add(dam_path)
        else:
            log("Skipping creating dam path {}".format(dam_path))

        status = _post_file(server, filepath, dam_path, options.dry_run)
        if status == OK:
            sys.stdout.write("{i}/{n} {local} -> {dam}\n".format(i=self.current_file, n=self.total_files,
                                                                 local=filepath, dam=dam_path))
            _touch(lock_file)

        return status
Пример #9
0
def fetch_tree_synchronous(server, options, content_path):
    """ Compount tool for fetching data immediately.
        Performs: Create, Fetch, Wait, Remove
    """
    task_id = create_task_id('rcp')

    status, data = _create_task(server, task_id, content_path, content_path,
                                options)
    if status != OK:
        error("Faiiled to fetch {} from {}".format(content_path,
                                                   options.source_host))
        return status

    status, task = get_task_status(server, task_id)
    log("Debug {}".format(json.dumps(task, indent=4)))
    if task['status']['state'] != 'NEW':
        error("Failed to locsate new task {}".format(task_id))
        return SERVER_ERROR

    status = start_task(server, task_id, options)
    if status != OK:
        error("Failed to fetch {} from {}, task {} did not start".format(
            content_path, options.source_host, task_id))
        return status

    wait_for_task(server, task_id)

    remove_task(server, task_id)
    return OK
Пример #10
0
def stop_task(server, task_id, options):
    """ Returns OK on success """
    log("Stopping task {}".format(task_id))
    status, content = post_command(server, task_id, 'stop')
    if options.raw:
        sys.stderr.write("{}\n".format(json.dumps(content)))
    return status
Пример #11
0
def _create_task(server, task_id, src_path, dst_path, options):
    """ Create a new task, does not start it """
    log("Creating task {}".format(task_id))
    payload = {
        "cmd":
        "create",
        "id":
        task_id,
        "src":
        "http://{credentials}@{source_host}/crx/-/jcr:root{content_path}".
        format(credentials=options.source_credentials,
               source_host=options.source_host,
               content_path=src_path),
        "dst":
        dst_path,
        "batchsize":
        int(options.batch_size),
        "update":
        options.overwrite_existing,
        "onlyNewer":
        options.respect_modified_date,
        "throttle":
        int(options.throttle),
        "recursive":
        True,
    }
    url = server.url("/system/jackrabbit/filevault/rcp")
    resp = requests.post(url, auth=server.auth, json=payload)
    if resp.status_code != 201:
        error("Failed to create task, request returned {} and {}".format(
            resp.status_code, resp.content))
        return SERVER_ERROR, None

    return OK, resp.json()
Пример #12
0
    def execute(self, server, argv):
        log("Executing {}".format(self.name))
        self.setopt(argv)

        try:
            ret = self.diff_subnodes(server, self.server2, self.path)
        except KeyboardInterrupt:
            return 0
Пример #13
0
def register_tool(_tool):
    assert get_tool(_tool.name) is None
    if _init_project is None:
        name = _tool.name
    else:
        name = _init_project + ':' + _tool.name
    log("Registering tool {}".format(name))
    _tools[name] = _tool
Пример #14
0
def register_tool(_tool):
    assert get_tool(_tool.name) is None
    if _init_project is None:
        name = _tool.name
    else:
        name = _init_project + ':' + _tool.name
    log("Registering tool {}".format(name))
    _tools[name] = _tool
Пример #15
0
def _touch(filename):
    """ Create empty file """
    par_dir = os.path.dirname(filename)
    if not os.path.exists(par_dir):
        log("Creating directory {}".format(par_dir))
        os.makedirs(par_dir, mode=0755)
    log("Creating lock file {}".format(filename))
    open(filename, 'a').close()
Пример #16
0
    def _fetch_json(self, url):
        log("Fetching url {}".format(url))
        resp = requests.get(url, auth=self.server.auth)

        if resp.status_code != 200:
            return SERVER_ERROR, None

        data = json.loads(resp.content)
        return OK, data
Пример #17
0
def _infer_type(val):
    if val.lower() == 'true' or val.lower() == 'false':
        log("Setting boolean typehint")
        return 'Boolean'
    elif val.isdigit():
        log("Setting integer typehint")
        return 'Long'
    else:
        return None
Пример #18
0
def start_bundle(server, bundlename, options):
    """ curl -u admin:admin http://localhost:4505/system/console/bundles/org.apache.sling.scripting.jsp
        -F action=start."""
    form_data = {'action': 'start'}
    url = server.url('/system/console/bundles/{bundle}'.format(bundle=bundlename))
    log("POSTing to service {}".format(url))
    resp = requests.post(url, auth=(server.username, server.password), data=form_data)
    if options.raw:
        sys.stdout.write("{}\n".format(resp.content))
Пример #19
0
def deploy_bash_completion(paths=None):
    """ Find the bash_completion.d directory and install the packaged script.
    """
    path = _locate_bash_completion_dir(paths)
    if path is not None:
        acmd.log("Found bash completion script dir {}".format(path))
        install_script(path)
        return path
    else:
        sys.stderr.write("Could not find bash completion install dir.")
Пример #20
0
def get_bundle_list(server):
    url = server.url('/system/console/bundles.json')

    log("GETting service {}".format(url))
    response = requests.get(url, auth=server.auth)

    if response.status_code != 200:
        error("Failed to list bundles: {}".format(response.status_code))
        return []
    bundles = response.json()['data']
    return bundles
Пример #21
0
def _get_subnodes(server, path):
    url = server.url("{path}.1.json".format(path=path))

    log("GETting service {}".format(url))
    resp = requests.get(url, auth=server.auth)

    if resp.status_code != 200:
        sys.stderr.write("error: Failed to get path {}, request returned {}\n".format(path, resp.status_code))
        sys.exit(-1)

    return resp.json()
Пример #22
0
    def execute(self, server, argv):
        options, args = parser.parse_args(argv)
        if options.lock_dir is not None:
            self.lock_dir = options.lock_dir
        log("Cache dir is {}".format(self.lock_dir))
        action = get_command(args)
        actionarg = get_argument(args)

        if action == 'import':
            return self.import_path(server, options, actionarg)
        return OK
Пример #23
0
 def execute(self, server, argv):
     log("Executing {}".format(self.name))
     options, args = parser.parse_args(argv)
     if len(args) >= 2:
         path = args[1]
         return list_node(server, options, path)
     else:
         ret = OK
         for path in sys.stdin:
             ret = ret | list_node(server, options, path.strip())
         return ret
Пример #24
0
def _get_subnodes(server, path):
    url = server.url("{path}.1.json".format(path=path))

    log("GETting service {}".format(url))
    resp = requests.get(url, auth=server.auth)

    if resp.status_code != 200:
        sys.stderr.write("error: Failed to get path {}, request returned {}\n".format(path, resp.status_code))
        sys.exit(-1)

    return resp.json()
Пример #25
0
 def execute(self, server, argv):
     log("Executing {}".format(self.name))
     options, args = parser.parse_args(argv)
     if len(args) >= 2:
         path = args[1]
         return list_node(server, options, path)
     else:
         ret = OK
         for path in sys.stdin:
             ret = ret | list_node(server, options, path.strip())
         return ret
Пример #26
0
def _get_bash_version():
    """ Find version of bash currently running. """
    try:
        full_text = subprocess.check_output(['bash', '--version'])
        first_line = full_text.split('\n')[0]
        version_string = first_line.lstrip("GNU bash, version ")
        major = LooseVersion(version_string).version[0]
        return major
    except Exception as e:
        acmd.log("No bash was found: " + e.message)
        return 0
Пример #27
0
def delete_package(server, options, package_name):
    url = get_package_url(package_name, server, options)
    form_data = dict(cmd='delete')

    log("Deleting package with POST to {}".format(url))
    resp = requests.post(url, auth=server.auth, data=form_data)
    if resp.status_code != 200:
        error("Failed to delete package: {}".format(resp.content))
        return SERVER_ERROR
    if options.raw:
        sys.stdout.write("{}\n".format(resp.content))
    return OK
Пример #28
0
def _get_task_list(server):
    url = server.url("/system/jackrabbit/filevault/rcp")

    log("GETting service {}".format(url))
    resp = requests.get(url, auth=server.auth)

    if resp.status_code != 200:
        error("Failed to list rcp tasks, request returned {}".format(
            resp.status_code))
        return SERVER_ERROR, None

    return OK, resp.json()
Пример #29
0
def parse_properties(props_str):
    """ Translate command line properties string to dictionary.
            example: prop0=value,prop1="Quoted value"
    """
    log("Parsing props string '{}'".format(props_str))
    ret = dict()
    rest = props_str
    while rest.strip() != '':
        key, val, rest = _parse_property(rest)
        log("    setting {}={}".format(key, val))
        ret[key] = val
    return ret
Пример #30
0
def delete_package(server, options, package_name):
    url = get_package_url(package_name, server, options)
    form_data = dict(cmd='delete')

    log("Deleting package with POST to {}".format(url))
    resp = requests.post(url, auth=server.auth, data=form_data)
    if resp.status_code != 200:
        error("Failed to delete package: {}".format(resp.content))
        return SERVER_ERROR
    if options.raw:
        sys.stdout.write("{}\n".format(resp.content))
    return OK
Пример #31
0
    def import_path(self, path):
        """ Import generic file system path, could be file or dir """
        if self.dry_run:
            log("Dry running import")

        if os.path.isdir(path):
            return self.import_directory(path)
        else:
            import_root = os.path.dirname(path)
            if self.destination_root is not None:
                import_root = self.destination_root
            return self.import_file(import_root, path)
Пример #32
0
    def execute(self, server, argv):
        self.api = AssetsApi(server)

        options, args = parser.parse_args(argv)

        action = get_action(args)
        actionarg = get_argument(args)

        if action == 'import':
            funnel = AssetsImportFunnel(server, dry_run=options.dry_run, destination_root=options.destination_root)
            return funnel.import_path(actionarg)
        elif action == 'touch':
            api = WorkflowsApi(server)
            if len(args) >= 3:
                self.touch_asset(api, actionarg, options.model)
            else:
                for line in sys.stdin:
                    self.touch_asset(api, line.strip(), options.model)
            return OK
        elif action == 'list' or action == 'ls':
            status, data = self.api._list_assets(actionarg)
            if status != OK:
                return status
            for item in data['entities']:
                sys.stdout.write("{}\n".format(item['properties']['name']))
            return OK
        elif action == 'find':
            status, data = self.api.find(actionarg)
            if status != OK:
                return status
            for item in data:
                props = item['properties']
                path = acmd.jcr.path.join(props['path'], props['name'])
                sys.stdout.write("{}\n".format(path))
            return OK
        elif action == 'tag':
            tag_str = get_argument(args)
            status, tags = parse_tags(tag_str)
            if status != OK:
                return status
            if len(args) <= 3:
                log("Reading files from input")
                for path in sys.stdin:
                    path = path.strip()
                    self.tag_asset(path, tags)
            else:
                path = get_argument(args, i=3)
                self.tag_asset(path, tags)
            return OK
        else:
            error("Unknown action {}".format(action))
            return USER_ERROR
Пример #33
0
def run(options, config, args, cmdargs):
    tool_name, args = args[1], []
    server = config.get_server(options.server)
    if server is None:
        sys.stderr.write("error: server '{srv}' not found.\n".format(srv=options.server))
        return acmd.USER_ERROR
    acmd.log("Using server {}".format(server))
    cmd = acmd.get_tool(tool_name)
    if cmd is None:
        sys.stderr.write("error: tool '{cmd}' not found.\n".format(cmd=tool_name))
        return acmd.USER_ERROR
    else:
        return cmd.execute(server, cmdargs)
Пример #34
0
def load_projects(projects):
    """ Load any user specified tools directories.
        Expecting dict of {<prefix>: <path>} """
    ret = {}
    for name, path in projects.items():
        acmd.log("Loading project {}".format(name))
        path = os.path.expanduser(path)
        sys.path.insert(1, path)
        init_file = os.path.join(path, '__init__.py')
        acmd.set_current_project(name)
        acmd.import_tools(init_file)
        ret[name] = path
    return ret
Пример #35
0
def create_dir(server, path, dry_run):
    """ Create file in the DAM
        e.g. curl -s -u admin:admin -X POST -F "jcr:primaryType=sling:OrderedFolder" $HOST$dampath > /dev/null
    """
    if dry_run:
        log("SKipping creating folder, dry run")
        return

    form_data = {'jcr:primaryType': 'sling:OrderedFolder'}
    url = server.url(path)
    log("POSTing to {}".format(url))
    resp = requests.post(url, auth=server.auth, data=form_data)
    if not _ok(resp.status_code):
        raise AssetException("Failed to create directory {}\n{}".format(url, resp.content))
Пример #36
0
def create_dir(server, path, dry_run):
    """ Create file in the DAM
        e.g. curl -s -u admin:admin -X POST -F "jcr:primaryType=sling:OrderedFolder" $HOST$dampath > /dev/null
    """
    if dry_run:
        log("SKipping creating folder, dry run")
        return

    form_data = {'jcr:primaryType': 'sling:OrderedFolder'}
    url = server.url(path)
    log("POSTing to {}".format(url))
    resp = requests.post(url, auth=server.auth, data=form_data)
    if not _ok(resp.status_code):
        raise AssetException("Failed to create directory {}\n{}".format(
            url, resp.content))
Пример #37
0
def _create_dir(server, path, dry_run):
    """ Create file in the DAM
        e.g. curl -s -u admin:admin -X POST -F "jcr:primaryType=sling:OrderedFolder" $HOST$dampath > /dev/null
    """
    if dry_run:
        return OK

    form_data = {'jcr:primaryType': 'sling:OrderedFolder'}
    url = server.url(path)
    log("POSTing to {}".format(url))
    resp = requests.post(url, auth=server.auth, data=form_data)
    if not _ok(resp.status_code):
        error("Failed to create directory {}\n{}".format(url, resp.content))
        return SERVER_ERROR
    return OK
Пример #38
0
    def get_subnodes(self, server, path):
        url = server.url("{}.1.json".format(path))

        log("GETting service {}".format(url))
        resp = requests.get(url, auth=server.auth)
        if self.options.raw:
            print "{} {} {}".format(resp.url, resp.status_code, resp.encoding)
            print "{}".format(resp.text)
            if resp.status_code == 200:
                print "{}".format(resp.json())

        if resp.status_code != 200:
            raise Exception(
                "error: Failed to get path {}{}, request returned {}\n".format(server, path, resp.status_code)
            )

        return resp.json()
Пример #39
0
def install_package(server, options, package_name):
    """ curl -u admin:admin -X POST \
        http://localhost:4505/crx/packmgr/service/.json/etc/packages/export/name of package?cmd=install """
    url = get_package_url(package_name, server, options)
    form_data = dict(cmd="install")

    log("Installing package with POST to {}".format(url))
    resp = requests.post(url, auth=server.auth, data=form_data)
    if resp.status_code != 200:
        error("Failed to install package: {}".format(resp.content))
        return SERVER_ERROR
    data = resp.json()
    assert data["success"] is True
    if options.raw:
        sys.stdout.write("{}\n".format(resp.content))
    else:
        sys.stdout.write("{}\n".format(data["msg"]))
    return OK
Пример #40
0
def start_workflow(server, options, model, path):
    task_id = create_task_id(model)

    form_data = dict(
        model='/etc/workflow/models/{}/jcr:content/model'.format(model),
        payload=_asset_path(path),
        payloadType='JCR_PATH',
        workflowTitle=task_id,
        startComment=''
    )
    log(_asset_path(path))
    
    url = server.url(INSTANCES_PATH)
    resp = requests.post(url, auth=server.auth, data=form_data)
    if resp.status_code != 201:
        error("Unexpected error code {code}: {content}".format(
            code=resp.status_code, content=resp.content))
        return SERVER_ERROR

    output = resp.content if options.raw else task_id
    sys.stdout.write("{}\n".format(output))
    return OK
Пример #41
0
def post_file(server, filepath, dst_path, dry_run):
    """ POST single file to DAM
        curl -v -u admin:admin -X POST -i -F "file=@\"$FILENAME\"" $HOST$dampath.createasset.html &> $tempfile
    """
    assert os.path.isfile(filepath)

    if dry_run:
        return OK

    filename = os.path.basename(filepath)
    f = open(filepath, 'rb')
    mime, enc = mimetypes.guess_type(filepath)
    log("Uploading {} as {}, {}".format(f, mime, enc))
    form_data = dict(
        file=(filename, f, mime, dict()),
        fileName=clean_path(filename)
    )

    url = server.url("{path}.createasset.html".format(path=dst_path, filename=os.path.basename(filepath)))
    log("POSTing to {}".format(url))
    resp = requests.post(url, auth=server.auth, files=form_data)
    if not _ok(resp.status_code):
        raise AssetException("Failed to upload file {}\n{}".format(filepath, resp.content))
    return OK
Пример #42
0
def upload_package(server, options, filename):
    """ curl -u admin:admin -F file=@"name of zip file" -F name="name of package"
            -F force=true -F install=false http://localhost:4505/crx/packmgr/service.jsp """
    form_data = dict(
        file=(filename, open(filename, "rb"), "application/zip", dict()),
        name=filename.rstrip(".zip"),
        force=json_bool(options.install),
        install=json_bool(options.install),
    )
    log(form_data)
    url = server.url(SERVICE_PATH)
    resp = requests.post(url, auth=server.auth, files=form_data)

    if resp.status_code != 200:
        error("Failed to upload paackage: {}: {}".format(resp.status_code, resp.content))
        return SERVER_ERROR
    if options.raw:
        sys.stdout.write("{}\n".format(resp.content))
    else:
        tree = ElementTree.fromstring(resp.content)
        pkg_elem = tree.find("response").find("data").find("package")
        pkg = parse_package(pkg_elem)
        sys.stdout.write("{}\n".format(format_package(pkg)))
    return OK
Пример #43
0
def activate(server, options, path):
    """ curl -u admin:admin -X POST -F path="/content/path/to/page" -F cmd="activate" http://localhost:4502/bin/replicate.json
    """
    url = server.url(SERVICE_PATH)
    form_data = dict(cmd='activate',
                     path=path,
                     ignoredeactivated='false',
                     onlymodified='false')

    resp = requests.post(url, auth=server.auth, data=form_data)
    if not resp.status_code == 200:
        error("Failed to perform activation because {}: {}\n".format(resp.status_code, resp.content))
    else:
        if options.raw:
            sys.stdout.write("{}\n".format(resp.content))
        else:
            tree = html.fromstring(resp.text)
            paths = tree.xpath("//body/div/div[@class='path']/text()")
            paths = [path.split(' ')[0] for path in paths]
            paths = filter(lambda path: path.strip() != '', paths)
            msg = '\n'.join(paths)
            log("{}".format(msg))

            sys.stdout.write("{}\n".format(msg))
Пример #44
0
def split_argv(argv):
    """ Split argument list into system arguments before the tool
        and tool arguments afterwards.
        ['foo', 'bar', 'inspect', 'bink', 'bonk']
            => (['foo', 'bar', 'inspect'], ['inspect', 'bink', 'bonk'])"""
    acmd.log("Splitting {}".format(argv))
    for i, arg in enumerate(argv):
        acmd.log("Checking for {}".format(arg))
        if acmd.tool_repo.has_tool(arg):
            left = argv[0:i + 1]
            right = argv[i:]
            acmd.log("Splitting args in {} and {}".format(left, right))
            return left, right
    return argv, []