LoginSignup
1
1

More than 3 years have passed since last update.

GitLabプライベートリポジトリのrawリンクをCLIでダウンロードする

Last updated at Posted at 2020-02-13

Download gitlab private repository's raw link using CLI

GitLab 11.5.1から、PRIVATE-TOKENヘッダを使用してrawリンクのダウンロードができなくなりました (cf https://about.gitlab.com/releases/2018/11/28/security-release-gitlab-11-dot-5-dot-1-released/ Improper Enforcement of Token Scope)。
rawリンクが渡されたらURLをパース・変換して、ついでにファイル自体もダウンロードもできるようにしてみました。

#!/usr/bin/python
#gitlab_download

import os
import sys
import json
import shutil
from contextlib import closing

if sys.version_info[0]>=3:
    import http.client as httplib
    from urllib.request import urlparse
    binstdout = sys.stdout.buffer
else:
    import httplib
    from urlparse import urlparse
    binstdout = sys.stdout

def parse_gitlaburl(urlstr):
    url = urlparse(urlstr)
    a=url.path[1:].split('/')
    projname='/'.join([a[0],a[1]])
    if a[2]=='-':
        a.pop(2)
    if a[2]=='raw' or a[2]=='blob':
        revision=a[3]
        filepath='%2F'.join(a[4:])
        url_suffix='/repository/files/'+filepath+'/raw?ref='+revision
    elif a[2]=='jobs':
        assert a[4]=='artifacts'
        jobID=a[3]
        if a[5]=='download':
            url_suffix='/jobs/'+jobID+'/artifacts'
        elif a[5]=='raw' or a[5]=='file':
            filepath='/'.join(a[6:])
            url_suffix='/jobs/'+jobID+'/artifacts/'+filepath
        else:
            assert False
    else:
        raise Exception('unknown URL type %s'%a[2])
    return projname, url_suffix

def download_file(urlstr, token, fout):
    projname, url_suffix = parse_gitlaburl(urlstr)
    url = urlparse(urlstr)
    with closing(httplib.HTTPSConnection(url.hostname,port=url.port)) as https:
        https.request('GET','/api/v4/projects?search_namespaces=true&search='+projname,None,{'Authorization':'Bearer '+token})
        resp = https.getresponse()
        jso = json.loads(resp.read())
        proj = next(e for e in jso if e['path_with_namespace']==projname)
        resolvedPath = '/api/v4/projects/'+str(proj['id'])+url_suffix
        sys.stderr.write('resolved: https://%s%s\n'%(url.netloc,resolvedPath))
        https.request('GET',resolvedPath,None,{'Authorization':'Bearer '+token})
        resp = https.getresponse()
        #print(resp.getheaders())
        shutil.copyfileobj(resp,fout)

def get_token(**kwargs):
    url = urlparse(kwargs['url'])
    token = os.environ.get('gitlab_token_'+url.hostname.replace('.','_'),'')
    if not token:
        ### custom logic comes here
        pass
    return token

if __name__ == "__main__":
    token = get_token(url=sys.argv[1])
    download_file(sys.argv[1], token, binstdout)

200602

プロジェクト名からプロジェクトIDに変換する際、search_namespaces=trueを与えるようにしました。

210511

ci artifactをダウンロードできるようにしました。あと、再利用しやすくしました。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1