12. setup.py의 문제점
setup.py파일은 간단한 문자열 하나를 얻기 위해 많은 작업을 수행
일부 개발자들은 setup.py가 오직 인스톨 용도이거나, 또는 개발하는 동안만 쓸 목적일 수 도 있음.
$ python setup.py --name
Building lxml version 2.2.
NOTE: Trying to build without Cython, pre-generated 'src/lxml/lxml.etree.c'
needs to be available.
Using build configuration of libxslt 1.1.26
Building against libxml2/libxslt in the following directory: /usr/lib/lxml
15. PyPI 메타데이터
Name 프로젝트 이름
Version 릴리즈 버전
Summary 한 줄짜리 설명
Description 세부 설명
Home-Page 프로젝트 URL
Author 제작자 이름
Classifiers 프로젝트 구분자
Requires, Provides, Obsoletes 모듈들과의 의존성을 정의
19. 의존성 정의
from distutils.core import setup
setup(name='foo', version='1.0', requires=['win32com'])
리눅스에 설치한다면??
20. 의존성 정의
from distutils.core import setup
import sys
if sys.platform == 'win32':
setup(name='foo', version='1.0', requires=['win32com'])
else:
setup(name='foo', version='1.0')
21. 의존성 정의
from distutils.core import setup
import sys
if sys.platform == 'win32':
setup(name='foo', version='1.0', requires=['win32com'])
else:
setup(name='foo', version='1.0')
클라이언트에서 컴파일을 해봐야만 알 수 있다.
윈도우에 의존적임을 PyPI에 알려줄 방법이 없음
39. 실행환경 정의
메타데이터에 플랫폼 의존성 정의
Requires-Dist: pywin32 (>1.0); sys.platform == 'win32'
Obsoletes-Dist: pywin31; sys.platform == 'win32'
Requires-Dist: foo (1,!=1.3); platform.machine == 'i386'
Requires-Dist: bar; python_version == '2.4' or python_version == '2.5'
Requires-External: libxslt; 'linux' in sys.platform
40. 설치 포맷
여러 패키징 툴 간의 호환성을 위한 표준
METADATA 메타데이터 기술
RECORD 설치한 파일 목록
INSTALLER 설치한 툴 이름
REQUESTED 직접 설치한건지 여부
패키징 툴에 독립적으로 프로젝트 관리
41. 데이터 파일 구조
import os
here = os.path.dirname(__file__)
cfg = open(os.path.join(here, 'config', 'mopy.cfg'))
42. 데이터 파일 구조
import os
here = os.path.dirname(__file__)
cfg = open(os.path.join(here, 'config', 'mopy.cfg'))
import os
import pkgutil
# Open the file located in config/mopy.cfg in the MPTools project
cfg = pkgutil.open('MPTools', 'config/mopy.cfg')
43. 데이터 파일 구조
import os
here = os.path.dirname(__file__)
cfg = open(os.path.join(here, 'config', 'mopy.cfg'))
import os
import pkgutil
# Open the file located in config/mopy.cfg in the MPTools project
cfg = pkgutil.open('MPTools', 'config/mopy.cfg')
RESOURCES config/mopy.cfg {confdir}/{distribution.name}
44.
45.
46. Distutils2
Setup.py는 더 이상 사용하지 않음.
setup.cfg에 ini파일 형식으로 메타데이터 기록
Python 3.3에 Packaging이란 이름으로 포함 예정??
47. setup.cfg
[metadata]
name = MPTools
version = 0.1
author = Tarek Ziade
author-email = tarek@mozilla.com
summary = Set of tools to build Mozilla Services apps
description-file = README
home-page = http://bitbucket.org/tarek/pypi2rpm
project-url: Repository, http://hg.mozilla.org/services/server-devtools
classifier = Development Status :: 3 - Alpha
License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1)
50. 미러링 서버 구성
호스트 이름
X.pypi.python.org
X는 a, b, c, …, aa, ab, …의 시퀀스
last.pypi.python.org : 마지막 미러 서버
>>> import socket
>>> socket.gethostbyname_ex('last.pypi.python.org')[0]
'g.pypi.python.org'
>>>
51. 미러링 서버 구성
동기화
변경된 패키지만 동기화
/simple
/packages
통계 전파
다운로드 횟수
마스터 서버에서 stats디렉토리에 방문하여 수집
52.
53. 보안 위협
중앙 인덱스 서버가 탈취되었을 가능성
미러가 조작되었을 가능성
중간자 공격(Man in the Middle Attack)
54. 패키지 검증
1. /simple 페이지를 다운로드하여 SHA-1 해시를 계산한다.
2. 해당 해시의 DSA 시그니처를 계산한다.
3. /serversig 와 일치하는 것을 다운로드하여 2단계에서 계산된 것
과 바이트 단위로 비교한다.
4. 미러서버에서 다운로드한 모든 파일에 대한 MD5 해시를 계산하
고 검증한다.
이 책에선 제품의 인스톨 방식이 두가지가 있다고 그래요.1.이 책에서 두가지로 분류하고 있음.2. 정확한 용어는 나와있지 않음.3. 그래서 그 두가지가 무슨 차이가 있냐4. 유지관리가 용이. ex)라이브러리보안패치5. 안정적임 : 의존성을 직접 제어 할 수 있음6. 패키지: 개발자, 시스템관리자 친화적스탠드얼론 : 엔드유저 친화적
1.이 책에서 두가지로 분류하고 있음.2. 정확한 용어는 나와있지 않음.3. 그래서 그 두가지가 무슨 차이가 있냐4. 유지관리가 용이. ex)라이브러리보안패치5. 안정적임 : 의존성을 직접 제어 할 수 있음6. 패키지: 개발자, 시스템관리자 친화적스탠드얼론 : 엔드유저 친화적
이상적인 패키징 시스템이란 무엇인가.우선 플랫폼 독립적이어야 한다는 거예요.한번 패키징 스크립트를 작성해 놓으면,그거를 리눅스에서든 윈도우에서든 설치할 수가 있어야한다는거죠그리고 다시 패키징하는게 가능해야한다는거에요.가령뭐 소스나 리소스가 일부 수정되었을때 그겄들을 다시 쉽게 묶어낼수 있느냐 하는 관점이구요
다음은 비표준 패키징 시스템의 문제점인데만약 패키징시스템에 표준이 없다면 어떤일이 일어나느냐는 거예요.관리자도 시스템에 뭐가 있는지 모른다.-패키지시스템이 언인스톨을 지원안하면. 어떻게 지울까요?-어떤 패키지가 인스톨하면서 여러 다른 라이브러리나 프로그램들을 깔았어요. 근데뭐가 어디에있는지 하나도 알수가 없는거죠.
Distutils : 기본으로 들어있는 표준라이브러리
Distutils : 기본으로 들어있는 표준라이브러리그렇다면 Distutils에는 어떤 문제가 있었길래 이렇게 확장이 계속 됐냐.
자 그러면 파이썬 표준 라이브러리인 Distutils부터 볼께요과연 이 Distutils가 어떤 문제를 가지고 있었길래 저런setuptools가 나타나고 pip가 나타났는지 볼거에요
배포나 설치 방법 같은 거를 정의 하는 파일Helloworld데모
All in oneupload : 온라인리파지토리에배포판을업로드한다.register : 프로젝트의메타데이터를온라인리파지토리에등록한다. 배포판업로드는요구되지않는다.bdist : 바이너리배포판을생성한다.bdist_msi : 윈도우용 .msi파일을생성한다.
setup.py파일은간단한문자열하나를얻기위해많은작업을수행.(의존성있는 다른 라이브러리를 준비함. 사실 이건 인스톨을 위한건데, 실제 패키지 인스톨은 하지 않겠지만 패키지 인스톨을위한 기반 작업을 다 하고 있는거죠일부 개발자들은 setup.py가오직인스톨용도이거나, 또는개발하는동안만쓸목적일 수도 있음.그러면 일부기능밖에 작동 안할 수 있음.
제가 갑자기 PyPI를 설명한 이유는 이 의존성 정의 때문이예요. Requires에 ldap이라고 적은건 이 ldap이라는 모듈에 이 패키지가 의존성이 있다는 거구요.즉 필요하다는거죠. 그리고 그거는 PyPI서버에 있으니까 알아서 깔라는거고요.
이것만가지곤 어느 프로젝트의 ldap인지 알수가 없는거에요. 정말 허술하기 짝이 없죠
딱봐도 윈도우에 의존성이 있는 모듈이죠.
애초에 PyPI가 이건 윈도우 플랫폼 전용이라는걸 Distutils가 알아야 하지만 그걸 Distutils에 알려줄 방법이 없다.오로지 클라이언트에서 실행을 해봐야만 안되는걸 알 수 있다.그걸 알려줬다면 안받아 갈 수도 있었겠죠.
언인스톨이 안된대요. 참 이건 어처구니가 없죠.--record 옵션은 기본 값이 아님- 심지어 문서에서 거의 언급하지 않음.
우선 PyPI에 대해 알아보면
패키징 하는사람이 pypi에 패키지를 등록을 하고 업로드를해요. 그리고 유저는 서버에 접근해서 필요한 패키지를받아 가겠죠.
그래서 이렇게 Distutils라는 표준라이브러리가 불편한점이 있다보니까 새로운 라이브러리 들이 생긴거에요.아까 말했던 setuptools와 같은 얘들이죠.지금 부터는 걔네들은 어땠는지 한번 볼께요.
더 많은 PyPI부하 : 연결된 프로젝트의 의존성체크를 확인하기 위해 해당프로젝트의 setup.py를 다운받아서 다시 실행해봄. 이것을 재귀적으로.롤백이 되지 않음 : 의존성을 설치하다가 실패하면 그대로 중단.하지만 대부분은 이런게 크게 문제가 되지 않았기 때문에 setuptools는 가장 광범위하게 쓰임
언인스톨러의 제공을 위해서 새로운 메타파일 형식을 또 만들어 냈어요.이 파일은 설치한 파일들에 대한 히스토리를 모두 남긴거겠죠.
다음으로 Distutils가 가진 또다른 문제가 하나 있었는데데이터 파일들의 경로에 관련된 거에요
리패키징하기위해서는 setup.py를 분석해야한다.-특정데이터들이 어디에 있는지 어떤것들인지 분석이 필요함. 사실 데이터파일 정보만 따로 떨어져 있다면 좋을텐데-심지어 setup.py가 아니라 프로젝트 코드를 봐야 할 수도 있음.-그리고 경로를 수정하기로 마음먹었다면 모든 소스코드의 라인을 수정해야함. 개발자가 지정한 상대경로로 짜여져 있을테니까데이터파일의 분류가 없다-이미지인지 Man페이지인지 기타 다른파일인지 신경안씀
리패키징하기위해서는 setup.py를 분석해야한다.-특정데이터들이 어디에 있는지 어떤것들인지 분석이 필요함. 사실 데이터파일 정보만 따로 떨어져 있다면 좋을텐데-심지어 setup.py가 아니라 프로젝트 코드를 봐야 할 수도 있음.-그리고 경로를 수정하기로 마음먹었다면 모든 소스코드의 라인을 수정해야함. 개발자가 지정한 상대경로로 짜여져 있을테니까데이터파일의 분류가 없다-이미지인지 Man페이지인지 기타 다른파일인지 신경안씀
그래서 이렇게 표준이 해야 할 일을 표준이 못하니까 각종 패키징 라이브러리들이 판을 쳤어요근데 정작 문제는 해결이 안되고 점점 커져만 간거예요.다양한 패키징 툴이 존재하니까 포맷이 여러개라서 복잡해졌죠.그래서 이런 문제들을 근본적으로 다 뜯어 고치기 위해서 새로운 표준이 필요했어요.이 챕터의 저자는 이러한 새로운 표준을 만들어낸 사람이에요이러한 문제점들을 어떻게 고쳐나갔는지 설명할 거예요
The Python Enhancement Proposals어떤 기능에 대한 문서라든가, 파이썬을 사용하는데 있어서의 권고사항이라든가가 정리되는 문서예요 PEP386은 그 문서번호고
Provides-Dist는 한 프로젝트에 다른 프로젝트를 병합할때 쓰임. 가령 DB관련 라이브러리에 transaction라이브러리를 포함할 때Obsoletes-Dist는더이상사용하지않는다른프로젝트를지정하는데쓰인다 : 프로젝트의 이름이 바뀌었을때
여러 패키징 시스템간의 호환성을 위한 표준이에요가령 앞에서 distutils랑 setuptools랑 pip가 있었잖아요. 근데 다들 제각각의 포맷으로 설치정보를 기록했어요그니깐 Pip로 설치한거를 setuptools로 읽지 못하고 setuptools로 설치한거는 distutils에서 읽지 못하고그런문제가 있었다는거죠그래서 메타데이터는 어떻게 생겨야 하고설치한 파일 레코드는 어떻게 기록이 되어야 하는지를 다 표준으로 정의한거예요.그래서 이러한 표준으로 인해 패키징 툴에 독립적으로 프로젝트 관리
아까 봤던건데어떤 프로젝트에서 자기 프로젝트의 리소르를 쓰는데 지금 이거는 그 리소스 파일의 경로를 하드코딩한거예요.
'config/mopy.cfg‘는 하나의 변수가 된거예요. 다른 경로로의 매핑이죠.
'config/mopy.cfg‘는 하나의 변수가 된거예요. 다른 경로로의 매핑이죠.
여기에 리소스 경로는 이미 설치된 후의 파일경로를 기록한 것임그렇다면 저 경로는 어떻게 만들어 냈느냐다음을 보시면 되요
근데 {confdir}은 또 변수명이잖아요? 그 변수명은 어디있느냐그건 인스톨러가 sysconfig모듈을 이용을 해서 sysconfig.cfg를 읽는거에요.그럼 sysconfig.cfg에는 시스템 기본값이 적혀있어요. 이 기본값은 OS별로 각각 다르게 정의 되겠죠.이제 패키지 관리자는 setup.py를 뒤적거릴 필요가 없어요.이거를 설치하는 사람도 데이터파일 위치바꾸려고 setup.py를 뒤져서 수정할 필요가 없어요.setup.cfg만 수정하면 되요
아까 PyPI는 Single point of failure라고 해서 서버에 부하가 걸리면 PyPI서비스 자체를 이용을 할 수가 없다고 했죠그래서 그 해법으로 미러링 서버를 구축한거예요
동기화. 미러링 서버니까 데이터를 동기화 해서 공유 하겠죠. 정확히는 패키지를 공유하는데 변경된 패키지 데이터만 수집해서 동기화를 합니다. Changelog xml-rpc통계전파 : csv파일로 보관. 중앙 서버에서 stats디렉토리에 방문하여 수집
동기화 : xml-rpc
가능한 위협. 3가지가 있는데이러한 것들을 패키지를 서명하는 방식으로 검증을 할 수 있다고 합니다.
3. 그 dsa가 어떠한 값이어야 하는지 /serversig에 미리 저장이 되어져 있는거죠.
넓고복잡하게아키텍쳐를바꾸는것은 PEP 프로세스를통해표준을바꿈으로서조심스럽게행해져야한다.실제로 여기서 얘기하는 Distutils2도 몇 년이 걸렸다고해요.Setuptools는 별다른 PEP의 수정없이 Disturils의 메타데이터를 확장.그리고 그것이 기존 프로그램의 문제를 해결하기 위한 거였는데오히려 더 많은 문제를 초래했다는거죠하지만 아이러니 하게도 Setuptools의 그런 삽질 덕에 정말 수많은 피드백들을 받을수 있었고Distuils2를 어떻게 수정하면 좋을지 방향을 잡을 수 있었음.
표준 라이브러리의 패키지는 오래 못간다 라고 되있는데못가는 이유가표준라이브러리의 수정은 매우 어렵다2개의마이너파이썬버전후에 API를수정하거나제거할수있는프로세스도있다.distutils는 버려지는거임Distutils3을 만들지도