Tizen 2.0 Release accepted/tizen_2.0/20130215.201432 submit/tizen_2.0/20130215.192419
authorHyungKyu Song <hk76.song@samsung.com>
Fri, 15 Feb 2013 16:03:40 +0000 (01:03 +0900)
committerHyungKyu Song <hk76.song@samsung.com>
Fri, 15 Feb 2013 16:03:40 +0000 (01:03 +0900)
89 files changed:
Makefile
README.rst
data/tizen-1.0.conf [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/compat [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/docs [new file with mode: 0644]
debian/rules [new file with mode: 0644]
distfiles/debian/compat [new file with mode: 0644]
distfiles/debian/control [new file with mode: 0644]
distfiles/debian/copyright [new file with mode: 0644]
distfiles/debian/docs [new file with mode: 0644]
distfiles/debian/rules [new file with mode: 0755]
distfiles/gbs.conf [new file with mode: 0644]
distfiles/gbs.dsc [new file with mode: 0644]
distfiles/gbs.spec [new file with mode: 0644]
docs/GBS.rst [new file with mode: 0644]
docs/RELEASE_NOTES [new file with mode: 0644]
gitbuildsys/__init__.py [new file with mode: 0644]
gitbuildsys/cmd_build.py [new file with mode: 0644]
gitbuildsys/cmd_changelog.py [new file with mode: 0644]
gitbuildsys/cmd_chroot.py [new file with mode: 0644]
gitbuildsys/cmd_export.py [new file with mode: 0644]
gitbuildsys/cmd_import.py [new file with mode: 0644]
gitbuildsys/cmd_remotebuild.py [new file with mode: 0644]
gitbuildsys/cmd_submit.py [new file with mode: 0644]
gitbuildsys/conf.py [new file with mode: 0644]
gitbuildsys/errors.py [new file with mode: 0644]
gitbuildsys/msger.py [new file with mode: 0644]
gitbuildsys/oscapi.py [new file with mode: 0644]
gitbuildsys/parsing.py [new file with mode: 0644]
gitbuildsys/runner.py [new file with mode: 0644]
gitbuildsys/safe_url.py [new file with mode: 0644]
gitbuildsys/utils.py [new file with mode: 0644]
packaging/Makefile [new file with mode: 0644]
packaging/gbs.changes [new file with mode: 0644]
packaging/gbs.dsc [new file with mode: 0644]
packaging/gbs.spec [new symlink]
setup.cfg [new file with mode: 0644]
setup.py
tests/test_changelog.py [new file with mode: 0644]
tests/test_config.py [new file with mode: 0644]
tests/test_help.py [new file with mode: 0644]
tests/test_import.py [new file with mode: 0644]
tests/test_passwdx.py [new file with mode: 0644]
tests/test_profile.py [new file with mode: 0644]
tests/test_safe_url.py [new file with mode: 0644]
tests/testdata/ConsoleKit-0.4.5.zip [new file with mode: 0644]
tests/testdata/ail-0.2.29-2.3.src.rpm [new file with mode: 0644]
tests/testdata/ail-0.2.29-2.5.src.rpm [new file with mode: 0644]
tests/testdata/app-core-1.2-19.3.src.rpm [new file with mode: 0644]
tests/testdata/bad.spec [new file with mode: 0644]
tests/testdata/bad.src.rpm [new file with mode: 0644]
tests/testdata/bison-1.27.tar.gz [new file with mode: 0644]
tests/testdata/bluez_unpacked/Makefile [new file with mode: 0644]
tests/testdata/bluez_unpacked/bluetooth.init [new file with mode: 0644]
tests/testdata/bluez_unpacked/bluez-4.87.tar.gz [new file with mode: 0644]
tests/testdata/bluez_unpacked/bluez-fsync.patch [new file with mode: 0644]
tests/testdata/bluez_unpacked/bluez.changes [new file with mode: 0644]
tests/testdata/bluez_unpacked/bluez.spec [new file with mode: 0644]
tests/testdata/bluez_unpacked/bluez.yaml [new file with mode: 0644]
tests/testdata/bluez_unpacked/disable-hal-plugin.patch [new file with mode: 0644]
tests/testdata/bluez_unpacked/enable_HFP.patch [new file with mode: 0644]
tests/testdata/bluez_unpacked/install-more-binary-test.patch [new file with mode: 0644]
tests/testdata/bluez_unpacked/install-test-scripts.patch [new file with mode: 0644]
tests/testdata/bluez_unpacked/powered.patch [new file with mode: 0644]
tests/testdata/bluez_unpacked/remove-duplicate-wrong-udev-rule-for-dell-mice.patch [new file with mode: 0644]
tests/testdata/ini/bad_passwdx.ini [new file with mode: 0644]
tests/testdata/ini/bug387_inherit_only_passwdx.ini [new file with mode: 0644]
tests/testdata/ini/bug387_inherit_only_user.ini [new file with mode: 0644]
tests/testdata/ini/bug387_inline_auth_has_the_highest_priority.ini [new file with mode: 0644]
tests/testdata/ini/bug387_only_password_no_user.ini [new file with mode: 0644]
tests/testdata/ini/empty_passwdx.ini [new file with mode: 0644]
tests/testdata/ini/empty_profile.ini [new file with mode: 0644]
tests/testdata/ini/home1.ini [new file with mode: 0644]
tests/testdata/ini/interpolation.ini [new file with mode: 0644]
tests/testdata/ini/invalid_continuation_line.ini [new file with mode: 0644]
tests/testdata/ini/no_such_profile_section_name.ini [new file with mode: 0644]
tests/testdata/ini/normal_passwdx.ini [new file with mode: 0644]
tests/testdata/ini/passwdx.ini [new file with mode: 0644]
tests/testdata/ini/plain_passwd.ini [new file with mode: 0644]
tests/testdata/ini/plain_passwd2.ini [new file with mode: 0644]
tests/testdata/ini/profile.ini [new file with mode: 0644]
tests/testdata/ini/profile_only_has_api.ini [new file with mode: 0644]
tests/testdata/ini/project1.ini [new file with mode: 0644]
tests/testdata/ini/subcommand.ini [new file with mode: 0644]
tests/testdata/ini/without_section_header.ini [new file with mode: 0644]
tools/gbs [new file with mode: 0755]

index ba09813..49551d4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,14 +1,15 @@
-VERSION = $(shell cat VERSION)
-TAGVER = $(shell cat VERSION | sed -e "s/\([0-9\.]*\).*/\1/")
+VERSION = $(shell sed -ne 's/__version__\s*=\s*[\x22\x27]\([^\x22\x27]\+\)[\x22\x27].*/\1/p ' gitbuildsys/__init__.py)
+TAGVER = $(shell echo $(VERSION) | sed -e "s/\([0-9\.]*\).*/\1/")
+PKGNAME = gbs
 
 ifeq ($(VERSION), $(TAGVER))
        TAG = $(TAGVER)
 else
        TAG = "HEAD"
 endif
-
-ifeq (${PREFIX}, "")
-       PREFIX = "/usr/local"
+TAG="HEAD"
+ifndef PREFIX
+    PREFIX = "/usr/local"
 endif
 
 all:
@@ -17,13 +18,29 @@ all:
 tag:
        git tag $(VERSION)
 
-dist-bz2:
-       git archive --format=tar --prefix=tizenpkg-$(TAGVER)/ $(TAG) | \
-               bzip2  > tizenpkg-$(TAGVER).tar.bz2
+dist-common: man
+       git archive --format=tar --prefix=$(PKGNAME)-$(TAGVER)/ $(TAG) | tar xpf -
+       git show $(TAG) --oneline | head -1 > $(PKGNAME)-$(TAGVER)/commit-id
+       mkdir $(PKGNAME)-$(TAGVER)/doc; mv gbs.1 $(PKGNAME)-$(TAGVER)/doc
+
+dist-bz2: dist-common
+       tar jcpf $(PKGNAME)-$(TAGVER).tar.bz2 $(PKGNAME)-$(TAGVER)
+       rm -rf $(PKGNAME)-$(TAGVER)
+
+dist-gz: dist-common
+       tar zcpf $(PKGNAME)-$(TAGVER).tar.gz $(PKGNAME)-$(TAGVER)
+       rm -rf $(PKGNAME)-$(TAGVER)
+
+man:
+       rst2man docs/GBS.rst >docs/gbs.1
+
+html:
+       rst2html docs/GBS.rst >docs/gbs.html
+
+pdf:
+       rst2pdf docs/GBS.rst -o docs/gbs.pdf
 
-dist-gz:
-       git archive --format=tar --prefix=tizenpkg-$(TAGVER)/ $(TAG) | \
-               gzip  > tizenpkg-$(TAGVER).tar.gz
+docs: man html pdf
 
 install: all
        python setup.py install --prefix=${PREFIX}
@@ -35,3 +52,5 @@ clean:
        rm -rf build/
        rm -rf dist/
        rm -rf *.egg-info/
+test:
+       nosetests -v --with-coverage --with-xunit
index 1db3181..b847c42 100644 (file)
-========
-tizenpkg
-========
----------------------------------------------------
-The command line tools for Tizen package developers
----------------------------------------------------
+===
+gbs
+===
+---------------------------------------------------------------------
+git build system
+---------------------------------------------------------------------
 :Copyright: GPLv2
 :Manual section: 1
 
 Overview
 ========
-The command line tools for Tizen package developers
+git-build-system is a command line tools for Tizen package developers
+
+* gbs remotebuild : build rpm package from git repository on OBS
+* gbs build  : build rpm package from git repository at local
+* gbs import : import source rpm or specfile to git repository
+* gbs changelog   : generate changelog from git commits to changelog file
+* gbs submit : maintain the changelogs file, sanity check etc.
+* gbs export : export git tree as tar ball, format of tar ball is from spec
+
+It supports native running in many mainstream Linux distributions, including:
+
+* openSUSE (12.1
+* Ubuntu (11.10 and 12.04)
+
+Installation
+============
+gbs is recommended to install from official repository, but if your system have
+not been supported by official repo, you can try to install gbs from source
+code, before that, you should install gbs's dependencies such as git, osc, rpm,
+build.
+
+Repositories
+------------
+So far we support `gbs` binary rpms/debs for many popular Linux distributions,
+please see the following list:
+
+* openSUSE 12.1
+* Ubuntu 11.10
+* Ubuntu 12.04
+
+And you can get the corresponding repository on
+
+ `<http://download.tizen.org/tools/>`_
+
+If there is no the distribution you want in the list, please install it from
+source code.
+
+Binary Installation
+-------------------
+
+openSUSE Installation
+~~~~~~~~~~~~~~~~~~~~~
+1. Add Tools Building repo:
+::
+
+  $ sudo zypper addrepo http://download.tizen.org/tools/openSUSE12.1/ tools-building
+
+2. Update repolist:
+::
+
+  $ sudo zypper refresh
+
+3. Install gbs:
+::
+
+  $ sudo zypper install gbs
+
+Ubuntu Installation
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+1. Append repo source:
+::
+
+  Append the following line to /etc/apt/source.list:
+  #for ubuntu 11.10:
+  deb  http://download.tizen.org/tools/xUbuntu_11.10/ /
+  #for ubuntu 12.04
+  deb  http://download.tizen.org/tools/xUbuntu_12.04/ /
+
+2. Update repolist:
+::
+
+  $ sudo apt-get update
+
+3. Install gbs:
+::
+
+  $ sudo apt-get install gbs
+
+Source Installation
+-------------------
+If you need install gbs from source code, you need install gbs's dependencies
+first, required packages as follows:
+
+* git-core
+* osc >= 0.131
+* rpm
+* build
+
+Official osc are maintained at:
+
+ `<http://download.opensuse.org/repositories/openSUSE:/Tools/>`_
+
+which can be added to you system, then using general package manager tools
+to install osc.
+
+Gbs source code is managed by Gerrit in tizen staging zone(temporarily), you
+need an account to access it.
+
+Clone the source tree by:
+::
+
+  $ git clone ssh://<user_name>@review.stg.tizen.org:29418/gbs
+
+*Tips*: You need login the Gerrit and upload you public SSH key first
+and got your proxy setup.
+
+Then using the following commands to install gbs:
+::
+
+  $ cd gbs
+  $ sudo make install
+
+
+Configuration file
+==================
+gbs read gbs configure file from ~/.gbs.conf. At the first time to run the gbs,
+it will prompt you to input your user_name and password. Or edit the
+configuration file by yourself.  Just make sure it looks like as below:
+::
+
+  [general]
+  ; general settings
+  tmpdir = /var/tmp
+  [remotebuild]
+  ; settings for build subcommand
+  build_server = <OBS API URL>
+  user = <USER_NAME>
+  passwd  = <PASSWORD in plaintext> (will be updated w/ base64 encoded one)
+
+  [build]
+  su-wrapper= sudo
+  repo1.url=
+  repo1.user=
+  repo1.passwd=
+  repo2.url=
+  repo2.user=
+  repo2.passwd=
+
+In this configuration file, there are three sections: [common] is for general
+setting, [remotebuild] section is for the options of gbs remotebuild, and [build]
+is for gbs build.
+
+In the [remotebuild] section, the following values can be specified:
+
+build_server
+    OBS API url, which point to remote OBS. Available value can be:
+    https://build.tizen.org
+user
+    OBS account user name
+passwd
+    raw OBS account user passwd
+passwdx
+    encoded OBS account user passwd, this key would be generated automaticlly.
+
+In the [build] section, the following values can be specified:
+
+repox.url
+    Specify the repo url used for gbs build
+repox.user
+    Specify the user name for repox
+repox.passwd
+    Specify the passwd for repox
+
+Usages
+======
+It's recommended to use `--help` or `help <subcmd>` to get the help message,
+for the tool is more or less self-documented.
+
+Running 'gbs remotebuild'
+-------------------------
+
+Subcommand `remotebuild` is used to push local git code to remote obs build server
+to build. The usage of subcommand `remotebuild` can be available using `gbs remotebuild --help`
+::
+
+  remotebuild (rb): remote build package
+
+  Usage:
+      gbs remotebuild [options] [package git dir]
+
+  Options:
+      -h, --help          show this help message and exit
+      -B BASE_OBSPRJ, --base-obsprj=BASE_OBSPRJ
+                          Base OBS project being used to branch from, use
+                          "Tizen:Main" by default if not specified
+      -T TARGET_OBSPRJ, --target-obsprj=TARGET_OBSPRJ
+                          OBS target project being used to build package, use
+                          "home:<userid>:gbs:Tizen:Main" if not specified
+
+Before running gbs remotebuild, you need to prepare a package git repository
+first, and packaging directory must be exist and have spec file in it. The spec
+file is used to prepare package name, version and tar ball format, and tar ball
+format is specified using SOURCE field in specfile.
+
+Once git reposoritory and packaging directory are  ready,  goto  the  root
+directory of git repository, run gbs build as follows:
+::
+
+  $ gbs remotebuild
+  $ gbs remotebuild -B Test
+  $ gbs remotebuild -B Test -T home:<userid>:gbs
+
+Running 'gbs build'
+------------------------
+
+Subcommand `build` is used to build rpm package at local by rpmbuild. The
+usage of subcommand `build` can be available using `gbs build --help`
+::
+
+  build (lb): local build package
+  Usage:
+      gbs build -R repository -A arch [options] [package git dir]
+      [package git dir] is optional, if not specified, current dir would
+      be used.
+
+  Examples:
+      gbs build -R http://example1.org/packages/ \
+                -R http://example2.org/packages/ \
+                -A i586                          \
+                -D /usr/share/gbs/tizen-1.0.conf
+
+  Options:
+      -h, --help          show this help message and exit
+      --noinit            Skip initialization of build root and start with build
+                          immediately
+      -C, --clean         Delete old build root before initializing it
+      -A ARCH, --arch=ARCH
+                          build target arch
+      -B BUILDROOT, --buildroot=BUILDROOT
+                          Specify build rootdir to setup chroot environment
+      -R REPOSITORIES, --repository=REPOSITORIES
+                          Specify package repositories, Supported format is rpm-
+                          md
+      -D DIST, --dist=DIST
+                          Specify distribution configure file, which should be
+                          full path
+
+git repository and packaging directory should be prepared like `gbs build`.
+
+Examples to run gbs build:
+
+1) Use specified dist file in command line using -D option
+::
+
+  $ gbs build -R http://example1.org/ -A i586 -D /usr/share/gbs/tizen-1.0.conf
+
+2) Multi repos specified
+::
+
+  $ gbs lb -R http://example1.org/  -R http://example2.org/  -A i586
+
+3) With --noinit option, Skip initialization of build root and start with build immediately
+::
+
+  $ gbs build -R http://example1.org/ -A i586  --noinit
+
+4) Specify a package git directory, instead of running in git top directory
+::
+
+  $ gbs build -R http://example1.org/ -A i586  PackageKit
+
+5) Local repo example
+::
+
+  $ gbs build -R /path/to/repo/dir/ -A i586
+
+'''BKM''': to have quick test with local repo, you can run 'gbs build'
+with remote repo. rpm packages will be downloaded to localdir /var/cache/\
+build/md5-value/, then you can use the following command to create it as local
+repo
+::
+
+  $ mv /var/cache/build/md5-value/ /var/cache/build/localrepo
+  $ cd /var/cache/build/localrepo
+  $ createrepo . # if createrepo is not available, you should install it first
+  $ gbs build -R /var/cache/build/localrepo/ -A i586/armv7hl
+
+If gbs build fails with dependencies, you should download it manually and
+put it to /var/cache/build/localrepo, then createrepo again.
+
+Running 'gbs import'
+--------------------
+
+Subcommand `import` is used to import source rpm or unpacked \*.src.rpm to current
+git repository. This subcommand is mostly used for initializing git repository
+or upgrading packages. Usage of subcommand `import` can be available using
+`gbs import --help`
+::
+
+  import (im): Import spec file or source rpm to git repository
+
+  Usage:
+      gbs import [options] specfile | source rpm | tarball
+
+
+  Examples:
+    $ gbs import /path/to/specfile/
+    $ gbs import /path/to/*.src.rpm
+    $ gbs import /path/to/tarball
+  Options:
+      -h, --help          show this help message and exit
+      --tag               Create tag while importing new version of upstream tar
+                          ball
+      --upstream_branch=UPSTREAM_BRANCH
+                          specify upstream branch for new version of package
+      --author-email=AUTHOR_EMAIL
+                          author's email of git commit
+      --author-name=AUTHOR_NAME
+                          author's name of git commit
+
+
+Examples to run gbs import:
+
+1) import from source rpm, and package git repository would be generated
+::
+
+  $test@test/gbs-demo# gbs import expect-5.43.0-18.13.src.rpm
+   Info: unpack source rpm package: expect-5.43.0-18.13.src.rpm
+   Info: No git repository found, creating one.
+   Info: unpack upstream tar ball ...
+   Info: submitted the upstream data as first commit
+   Info: create upstream branch
+   Info: submit packaging files as second commit
+   Info: done.
+
+2) import from unpacked source rpm, spec file need to be specified from args
+::
+
+  $test@test/gbs-demo# gbs import expect-5.43.0/expect.spec --tag
+   Info: No git repository found, creating one.
+   Info: unpack upstream tar ball ...
+   Info: submitted the upstream data as first commit
+   Info: create tag named: 5.43.0
+   Info: create upstream branch
+   Info: submit packaging files as second commit
+   Info: done.
+  $test@test/gbs-demo# cd expect&git log
+   commit 3c344812d0fa53bd9c56ebd054998dc1b401ecde
+   Author: root <root@test-virtual-machine.(none)>
+   Date:   Sun Nov 27 00:34:25 2011 +0800
+
+        packaging files for tizen
+
+   commit b696a78b36ebd3d5614f0d3044834bb4e6bcd928
+   Author: root <root@test-virtual-machine.(none)>
+   Date:   Sun Nov 27 00:34:25 2011 +0800
+
+        Upstream version 5.43.0
+
+3) gbs import tarball must run under the top dir of package git repository, the
+following command can be used:
+::
+
+  $ cd example/
+  $ gbs import example-0.1.tar.gz
+  $ gbs import example-0.2-tizen.tar.bz2
+
+Running 'gbs changelog'
+-----------------------
+
+Subcommand `changelog` is used to generate changelog file in ./packaging dir.
+This subcommand is mostly used for create changelog before submit code.
+Usage of subcommand `changelog` can be available using
+`gbs changelog --help`
+::
+
+  changelog (ch): update the changelog file with the git commit messages
+
+  Usage:
+      gbs changelog [--since]
+
+  Examples:
+    $ gbs changelog
+    $ gbs changelog --since=COMMIT_ID
+  Options:
+      -h, --help          show this help message and exit
+      -s SINCE, --since=SINCE
+                          commit to start from
+
+Running 'gbs export'
+--------------------
+
+Subcommand `export` is used to export current working git tree as a tar ball.
+Usage of subcommand `export` can be available using `gbs changelog --help`
+::
+
+  test@test-desktop:~/$ gbs export -h
+  export (ex): export files and prepare for build
+
+  Usage:
+      gbs export
+
+  Note:
+
+  Options:
+      -h, --help          show this help message and exit
+      --spec=SPEC         Specify a spec file to use
+      -o OUTDIR, --outdir=OUTDIR
+                          Output directory
+
+Running 'gbs submit'
+--------------------
+
+Subcommand `submit` is used to submit local commits to gerrit for code review.
+Usage of subcommand `submit` can be available using `gbs changelog --help`
+::
+
+  test@test-desktop:~/$ gbs submit -h
+  submit (sr): submit commit request to gerrit for review
+
+  Usage:
+      gbs submit -m "msg for commit" [--changelog] [--tag]
+
+  Note:
+
+  Options:
+      -h, --help          show this help message and exit
+      --branch=TARGET_BRANCH
+                          specify the target branch for submit
+      --tag               make a tag before submit
+      -m MSG, --msg=MSG   specify commit message info
+      --changelog         invoke gbs changelog to create changelog
diff --git a/data/tizen-1.0.conf b/data/tizen-1.0.conf
new file mode 100644 (file)
index 0000000..98ed1e1
--- /dev/null
@@ -0,0 +1,420 @@
+Patterntype: rpm-md comps
+Release: <CI_CNT>.<B_CNT>
+Support: build build-compare
+
+
+Preinstall: libfile
+Support: libfile
+%ifarch %arm
+Preinstall: libfile-x86-arm
+Required: libfile-x86-arm
+%endif
+# 
+Substitute: gettext gettext-tools
+#Substitute: kernel-headers linux-headers
+
+
+Substitute: libncurses ncurses-libs 
+Substitute: libncurses-devel ncurses-devel
+Preinstall: nss 
+Ignore: bash:libncurses
+
+%ifarch armv7el
+Preinstall: nss-x86-arm nspr-x86-arm nss-softokn-freebl-x86-arm
+%endif
+
+Support: util-linux
+VMinstall: util-linux  libblkid libuuid
+
+ExportFilter: \.armv7hl\.rpm$ armv8el
+ExportFilter: \.armv7thl*\.rpm$ armv8el
+ExportFilter: \.armv7tnh*\.rpm$ armv8el
+ExportFilter: \.armv7h*\.rpm$ armv8el
+ExportFilter: \.armv7nh*\.rpm$ armv8el
+ExportFilter: \.x86_64\.rpm$ x86_64
+ExportFilter: \.i586\.rpm$ i586
+ExportFilter: \.armv5el\.rpm$ armv5el
+ExportFilter: \.armv5tel\.rpm$ armv5el
+ExportFilter: \.armv6el\.rpm$ armv6el
+ExportFilter: \.armv6l\.rpm$ armv6el
+ExportFilter: \.armv6vl\.rpm$ armv6el
+ExportFilter: \.armv7el\.rpm$ armv7el
+ExportFilter: \.armv7l\.rpm$ armv7el
+ExportFilter: \.armv7vl\.rpm$ armv7el
+# filter out packages of cross setup on ia32
+ExportFilter: .*vanish\.rpm
+PublishFilter: .*vanish\.rpm
+ExportFilter: .*dontuse\.rpm
+PublishFilter: .*dontuse\.rpm
+
+
+#
+# ARM Start
+#
+%ifarch %arm
+# arm land
+%define cross_5 1
+%define cross_7 1
+%define native 1
+
+%define cross_7h 1
+
+%ifarch armv8el
+Changetarget: armv7hl-tizen-linux
+%define _gnu gnueabi
+%if %{cross_7h}
+Prefer: cross-armv7hl-binutils-accel-armv7hl
+Prefer: cross-armv7hl-gcc-accel-armv7hl
+%define speedcommon 1
+%define speedbash 1
+%define speedbinutils 1
+%define speedgcc 1
+%define native 0
+%define speedtools 1
+Support: cross-armv7tnhl-platformfile
+%endif
+%endif
+
+
+########################
+# preselect rpm targets  
+# more ifs for _repository possible as needed  
+#########################  
+%ifarch armv5el
+Changetarget: armv5tel-tizen-linux
+%define _gnu gnueabi
+%if %{cross_5}
+%define speedcommon 1
+%define speedbash 1
+%define speedbinutils 1
+%define speedgcc 1
+%define native 0
+%endif
+%endif
+
+%ifarch armv6el
+Changetarget: armv6l-tizen-linux
+%define _gnu gnueabi
+%endif
+
+
+
+%ifarch armv7el
+Changetarget: armv7l-tizen-linux
+%define _gnu gnueabi
+%if %{cross_7}
+#Support: cross-armv7l-platformfile
+Prefer: cross-armv7l-binutils-accel-armv7l
+Prefer: cross-armv7l-gcc-accel-armv7l
+%define speedcommon 1
+%define speedbash 1
+%define speedbinutils 1
+%define speedgcc 1
+%define native 0
+%define speedtools 1
+%endif
+
+%endif
+
+%if %speedtools
+Support: patch-x86-arm findutils-x86-arm gawk-x86-arm fdupes-x86-arm 
+Preinstall: libfile-x86-arm
+Preinstall: rpm-libs-x86-arm
+Preinstall: bzip2-libs-x86-arm
+Preinstall: elfutils-libelf-x86-arm
+Preinstall: bzip2-x86-arm
+Preinstall: tar-x86-arm
+Preinstall: libgcc-x86-arm
+Preinstall: libacl-x86-arm
+Preinstall: libattr-x86-arm
+Preinstall: coreutils-x86-arm
+Preinstall: libcap-x86-arm
+Preinstall: liblua-x86-arm
+Preinstall: popt-x86-arm
+Preinstall: sed-x86-arm
+Preinstall: xz-libs-x86-arm
+Preinstall: zlib-x86-arm
+Preinstall: file
+Preinstall: diffutils-x86-arm
+Preinstall: file-x86-arm
+Preinstall: sqlite-x86-arm
+Required: bzip2-libs-x86-arm
+Required: elfutils-x86-arm
+Required: elfutils-libs-x86-arm
+Required: elfutils-libelf-x86-arm
+Required: diffutils-x86-arm
+Required: gzip-x86-arm
+Required: libgcc-x86-arm
+Required: libacl-x86-arm
+Required: libattr-x86-arm
+Required: coreutils-x86-arm
+Required: libcap-x86-arm
+Required: liblua-x86-arm
+Required: popt-x86-arm
+Required: xz-libs-x86-arm
+Required: zlib-x86-arm
+Required: file
+Required: file-x86-arm
+Required: libfile-x86-arm
+Required: sqlite-x86-arm
+Required: rpm-libs-x86-arm
+Required: rpm-x86-arm
+Required: rpm-build-x86-arm
+Runscripts: sed-x86-arm
+Runscripts: tar-x86-arm
+Runscripts: bzip2-x86-arm
+Runscripts: coreutils-x86-arm
+Runscripts: diffutils-x86-arm
+
+Preinstall: rpm-x86-arm
+Runscripts: rpm-x86-arm
+Runscripts: file-x86-arm
+
+Support: !rpmlint-mini
+Support: !rpmlint-mini-x86-arm
+Prefer: python-libs
+%endif
+
+
+%if %speedcommon
+# cross-compilation/speedup
+Preinstall: tizen-accelerator eglibc-x86-arm 
+Runscripts: tizen-accelerator
+Required: tizen-accelerator
+%endif
+
+%if %speedbash
+# bash
+Preinstall: ncurses-libs-x86-arm
+Preinstall: bash-x86-arm 
+Runscripts: bash-x86-arm
+%endif
+
+%if %speedbinutils
+Required: cross-arm-binutils-accel
+%endif
+
+%if %speedgcc
+Required: cross-arm-gcc-accel
+%endif
+
+Preinstall: rpm
+Preinstall: rpm-libs
+Required:   rpm
+Prefer:     rpm-libs
+Prefer:     rpm
+
+# now i586 land
+%else
+
+
+
+Ignore: ncurses-libs-x86 libncurses-x86
+Preinstall: rpm rpm-libs
+Required:   rpm
+%endif
+
+#
+# ARM End
+#
+
+Preinstall: setup filesystem
+
+Preinstall: bash bzip2 coreutils coreutils-su diffutils liblua
+Preinstall: eglibc eglibc-common libacl libattr
+Preinstall: libgcc libcap
+Preinstall: popt readline sed tar zlib sqlite
+
+Preinstall: ncurses-libs
+
+Preinstall: elfutils-libelf bzip2-libs libstdc++ libfile
+Preinstall: xz-libs
+
+Preinstall: nss nspr nss-softokn-freebl
+
+VMinstall: perl libblkid e2fsprogs-libs libuuid perl-libs grep libpcre 
+Required: binutils gcc eglibc rpm-build libtool
+
+Support: cpio gcc-c++ perl-libs perl   findutils
+Support: file findutils zlib bzip2 
+Support: gzip 
+Support: ncurses-libs
+Support: make  patch sed  gawk tar grep coreutils pkgconfig  autoconf automake
+Support: m4 libfile tzdata tizen-release
+Support: kernel-headers eglibc-headers
+Support: xz-lzma-compat
+
+Keep: binutils cpp  file findutils gawk gcc  gcc-c++
+Keep: gdbm gzip libada libunwind  eglibc-devel libpcre xz-lzma-compat 
+Keep: make  gmp libcap groff cpio
+Keep: patch rpm-build  nss nspr elfutils python grep libgcc gcc-c++ 
+Keep: kernel-headers eglibc-headers perl-libs
+Keep: pkgconfig glib2 tizen-rpm-config
+Keep: xz-lzma-compat
+Keep: mpc mpfr  
+Keep: cloog cloog-ppl ppl  
+Keep: nss-softokn-freebl
+Keep: setup
+
+# SLP
+Ignore: intltool:perl-libwww-perl
+# Build dependency cycle
+Ignore: rpm-build:xz
+Ignore: udev:udev-rules
+Ignore: xdg-utils:libcontentaction
+Ignore: cups:xinetd
+Ignore: cups:xinitd
+Ignore: alsa-lib:alsa-plugins-pulseaudio
+Ignore: tizen-cross-armv5tel-sysroot
+Ignore: nautilus:gvfs
+Ignore: polkit:ConsoleKit
+Ignore: iso-codes:xml-common
+Ignore: libzypp:gnupg
+Ignore: gvfs:gnome-disk-utility
+Ignore: firstboot:system-config-date
+Ignore: SDL:mkinitrd
+Ignore: SDL:kernel,kernel-netbook
+Ignore: pulseaudio:kernel
+Ignore: libzypp:expect
+
+Ignore: pulseaudio:rtkit
+Ignore: rpm:libcap
+Ignore: rpm-libs:libcap
+Ignore: fuse-sshfs:fastinit
+Ignore: dhcp:fastinit
+
+Ignore: libgnomeprint22:fastinit
+Ignore: gvfs:fastinit
+Ignore: gnome-desktop:gnome-user-docs
+Ignore: gnome-settings-daemon:gnome-control-center
+Ignore: avahi:fastinit
+Ignore: fastinit:udev
+Ignore: udev:fastinit
+Ignore: PackageKit:udev
+Ignore: cvs:vim-minimal
+Ignore: bluez:fastinit
+Ignore: aspell:aspell-en
+
+Ignore: fuse:kernel
+Ignore: fuse:fastinit
+Ignore: fastinit:module-init-tools
+Ignore: hwdata:module-init-tools
+Ignore: gzip:less
+Ignore: xmlto:text-www-browser 
+Ignore: docbook-utils:text-www-browser 
+Ignore: gtk2:hicolor-icon-theme
+Ignore: docbook-dtds:openjade
+Ignore: xmlto:passivetex
+Ignore: GConf-dbus:openldap
+Ignore: perl:rsyslog,tcsh,logrotate
+Ignore: rpm:curl,crontabs,logrotate
+Ignore: texinfo-tex:tetex
+Ignore: xorg-x11-server:hal-info
+Ignore: gcc:libgomp
+Ignore: autoconf:imake
+Ignore: ConsoleKit:dbus,dbus-devel
+Ignore: fastinit:kernel,udev,ethtool,mingetty
+Ignore: tetex:tetex-fonts,desktop-file-utils
+Ignore: pam:glib2
+
+Ignore: gettext-devel:libgcj,libstdc++-devel
+Ignore: pam-modules:resmgr
+Ignore: bind-utils:bind-libs
+Ignore: alsa:dialog,pciutils
+Ignore: portmap:syslogd
+Ignore: fontconfig:freetype2
+Ignore: fontconfig-devel:freetype2-devel
+Ignore: xorg-x11-libs:freetype2
+Ignore: xorg-x11:x11-tools,resmgr,xkeyboard-config,xorg-x11-Mesa,libusb,freetype2,libjpeg,libpng
+Ignore: arts:alsa,audiofile,resmgr,libogg,libvorbis
+Ignore: libxml2-devel:readline-devel
+Ignore: gnome-vfs2:gnome-mime-data,desktop-file-utils,cdparanoia,dbus-1,dbus-1-glib,krb5,hal,libsmbclient,fam,file_alteration
+Ignore: libgda:file_alteration
+Ignore: gnutls:lzo,libopencdk
+Ignore: libgnomecanvas-devel:glib-devel
+Ignore: libgnomeui:gnome-icon-theme,shared-mime-info
+Ignore: gnome-pilot:gnome-panel
+Ignore: postfix:pcre
+Ignore: docbook_4:iso_ent,sgml-skel,xmlcharent
+Ignore: docbook-xsl-stylesheets:xmlcharent
+Ignore: tetex:xorg-x11-libs,expat,fontconfig,freetype2,libjpeg,libpng,ghostscript-x11,xaw3d,gd,dialog,ed
+Ignore: mailx:smtp_daemon
+Ignore: cron:smtp_daemon
+
+
+
+Macros:
+%opensuse_bs 1
+%_default_patch_fuzz   2
+
+%tizen_version 1.0
+%tizen 1.0
+
+%vendor tizen
+%_vendor tizen
+
+# python main version
+%py_ver         %(echo `python -c "import sys; print sys.version[:3]"`)
+
+# directories
+%py_prefix      %(echo `python -c "import sys; print sys.prefix"`)
+%py_libdir      %{py_prefix}/lib/python%{py_ver}
+%py_incdir      /usr/include/python%{py_ver}
+%py_sitedir     %{py_libdir}/site-packages
+%py_dyndir      %{py_libdir}/lib-dynload
+
+# pure python modules compilation
+%py_comp        python -c "import compileall; import sys; compileall.compile_dir(sys.argv[1], ddir=sys.argv[1][len('$RPM_BUILD_ROOT'):])"
+%py_ocomp       python -O -c "import compileall; import sys; compileall.compile_dir(sys.argv[1], ddir=sys.argv[1][len('$RPM_BUILD_ROOT'):])"
+
+%ext_info .gz
+%ext_man .gz
+
+%info_add(:-:) test -x /sbin/install-info -a -f %{?2}%{?!2:%{_infodir}}/%{1}%ext_info && /sbin/install-info --info-dir=%{?2}%{?!2:%{_infodir}} %{?2}%{?!2:%{_infodir}}/%{1}%ext_info \
+%{nil}
+
+%info_del(:-:) test -x /sbin/install-info -a ! -f %{?2}%{?!2:%{_infodir}}/%{1}%ext_info && /sbin/install-info --quiet --delete --info-dir=%{?2}%{?!2:%{_infodir}} %{?2}%{?!2:%{_infodir}}/%{1}%ext_info \
+%{nil}
+
+%lang_package \
+%package locale \
+Summary: Translations and Locale for package %{name}\
+Group: Translations\
+AutoReqProv: 0\
+%description locale\
+This package provides translations for package %{name}.\
+%files locale -f %{name}.lang\
+%defattr(-,root,root,-)\
+%{nil}
+
+
+%docs_package \
+%package docs \
+Summary: Documentation for package %{name}\
+Group: Documentation\
+AutoReqProv: 0\
+%description docs\
+This package provides documentation for package %{name}.\
+%find_docs \
+%files docs -f documentation.list\
+%defattr(-,root,root,-)\
+%{nil}
+
+
+%_smp_mflags -j4
+
+
+%remove_docs \
+  rm -rf %{?buildroot:%{buildroot}}%{_infodir} \
+  rm -rf %{?buildroot:%{buildroot}}%{_defaultdocdir} \
+  rm -rf %{?buildroot:%{buildroot}}%{_datadir}/doc/%{name} \
+  rm -rf %{?buildroot:%{buildroot}}%{_datadir}/gtk-doc \
+  find %{?buildroot:%{buildroot}} -regex ".*/man/man./.*\.[0-9]" | xargs rm -f -- \
+  find %{?buildroot:%{buildroot}} -regex ".*/man/.*/man./.*\.[0-9]" | xargs rm -f -- \
+  find %{?buildroot:%{buildroot}} -regex ".*/man/man./.*\.[0-9]pm" | xargs rm -f --
+
+
+
+%__global_cflags -O2 -g -pipe -Wall  -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security  
+Optflags: armv7l %{__global_cflags}  -fmessage-length=0 -march=armv7-a -mtune=cortex-a8 -mlittle-endian  -mfpu=vfpv3 -mfloat-abi=softfp -D__SOFTFP__  
+
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..7af06be
--- /dev/null
@@ -0,0 +1,221 @@
+gbs (0.12-1) unstable; urgency=high
+  * upgrade to gbs v0.12, which contains the following bug fixing & features:
+    * support build rpm packages for incremental build
+    * --noinit support
+    * x86_64 support
+    * add --keep-packs to keep unused packages in buildroot
+    * show simple progress message for long time operations
+    * pristine-tar support
+    * patches generation for upstream branch exists
+    * add --define option to define macros for rpmbuild
+    * no hard code default base project
+    * modify changelog order to follow default order of git log
+    * change --spec to use only base file name
+    * ignore .gbs.conf in patch-generation
+    * cmd_import: enable importing patches
+    * remove output repo and buildroot info to depanneur
+    * bug fix:
+      - set TIZEN_BUILD_ROOT as abspath
+
+ -- Qiang Zhang <qiang.z.zhang@intel.com>  Mon, 26 Nov 2012 10:56:15 +0800
+
+gbs (0.11.1) unstable; urgency=high
+  * Upgrade to gbs v0.11.1, which contains the following bug fixing & features:
+    * depend on depanneur 0.2.1 to fix build break issue for 'osc build'
+
+ -- Qiang Zhang <qiang.z.zhang@intel.com>  Mon, 12 Nov  2012 10:56:15 +0800
+
+gbs (0.11) unstable; urgency=high
+  * Upgrade to gbs v0.11, which contains the following bug fixing & features:
+    * Add --spec in 'gbs build' to support building one spec file for packages
+      contains multiple spec files.
+    * Add --profile/-P in 'gbs build' to support building packages using specified
+      profile.
+    * support local buildroot configurable in config file. The 'buildroot' can
+      be set under the 'general' section as a global setting.
+    * more clear and readable error report for gbs build, including gbs export
+      error, expansion error and rpmbuild error.
+    * bug fix:
+      - fix plaintext passwd printed for some error cases
+      - fix gbs archive tar ball issue if using user defined macro in spec file
+      - fix request passwd again if one package build for a long time(>15 mins)
+      - fix sudo timeout issue, which will result in endless loop
+      - fix return 0 from depanneur even if error occurs
+      - unify display color of debug message in gbs and depanneur
+      - fix endless loop if package circle dependency exists
+      - fix gbs build error if '~' exist in build root path
+      - fix passwd conflict issue with multiple instance of 'gbs build'
+      - fix remotebuild can't run in sub-directory issue
+      - fix gbs build error with https_proxy trailing '/'
+      - fix gbs submit gives no error if there is no comment
+      - describe missing dependencies for gbs build
+      - support create project outside home:<user> if user have permission
+      - fix server's certificate traceback issue for gbs remotebuild
+
+ -- Qiang Zhang <qiang.z.zhang@intel.com>  Thu, 25 Oct  2012 10:56:15 +0800
+
+gbs (0.10) unstable; urgency=high
+  * Upgrade to gbs v0.10, which contains the following features:
+    * Re-designed gbs config format and parser to support multiple profile more flexible:
+      - Use profile oriented style of config
+      - Inherited config files supportted, three level support now: /etc/gbs.conf, ~/.gbs.conf
+        and $PWD/.gbs.conf
+    * integrate depanneur to gbs
+    * local full build support, including the following features:
+      - Multiple packages build
+      - Dependency build
+      - Parallel build
+      - Incremental build
+    * Patch/upstream tarball generation is enabled if "upstream" branch is found
+      - If "pristine-tar" branch is found, checkout the orig tarball using pristine-tar
+      - If "pristine-tar" branch is NOT found, generate the upstream tarball from a git tag matching the version
+      - If the "upstream" branch is NOT found, gbs/gbp uses the current logic
+    * If local repo specified, local repo is high priority when selecting packages
+    * Remove -A option for gbs chroot, and build root directory must be specified
+    * Code cleanup and refinements.
+    * bug fix.
+
+ -- Qiang Zhang <qiang.z.zhang@intel.com>  Tue, 18 Sep  2012 10:56:15 +0800
+
+gbs (0.9) unstable; urgency=high
+  * Upgrade to gbs v0.9, which contains the following features:
+    * Fedora support
+    * update build to 2012-08-10 version, which including featurs:
+      - prefix each build log line with the second since build started
+      - other refinements
+    * --out for `gbs build` to copy generated RPMs to specified directory
+    * --source-rpm supported in export subcommand to generate source
+    * Introduce a Temp class to create/cleanup temp file and directory.
+    * Use more standard way to transfer repository user/pass to build scripts and hidden passwd in build.
+    * Code cleanup and refinements.
+    * bug fix.
+
+ -- Qiang Zhang <qiang.z.zhang@intel.com>  Wed, 15 Aug  2012 10:56:15 +0800
+
+gbs (0.8.1) unstable; urgency=high
+
+  * Upgrade to gbs v0.8.1, which contains the following features:
+    * new subcommand 'submit' added, which can be used for developers
+      to submit code to OBS for building
+ -- Qiang Zhang <qiang.z.zhang@intel.com>  Wed, 1 Aug  2012 10:56:15 +0800
+
+gbs (0.8) unstable; urgency=high
+
+  * Upgrade to gbs v0.8, which contains the following features:
+    * moving remotebuild temp build files to packaging dir
+    * moving build root to $tmpdir/$user/gbs-buildroot.$arch
+    * support building un-commit changes with --including-all opt
+    * support building special commit id or tag
+    * gbs chroot support, user can chroot to the buildroot, and make
+      yuild, it is useful for the big packages
+    * support custom location of configuration file, user can specify
+      different conf besides using ~/.gbs.conf using -c global option
+    * developer to be able to view 'gbs remotebuild' log and build
+      status using gbs with --buildlog and status options
+    * --extra-packs supported for developer installing extra packages
+      to build root, for example: --extra-packs=zypper,vim , this is
+      very usefull for developer to make buildroot as a full development
+      envionment
+
+ -- Qiang Zhang <qiang.z.zhang@intel.com>  Fri, 13 Jul  2012 10:56:15 +0800
+
+gbs (0.7.1) unstable; urgency=high
+
+  * Upgrade to gbs v0.7.1, which contains the following features:
+    * download build conf from repos
+    * support new format of repo url, for example:
+      http://download.tizen.org/snapshots/trunk/latest/, which contains
+      builddata/build.xml metadata, and using this file different
+      archs repos can be built out, so user dont need update conf
+      if transfer build archs
+    * more error handling for conf module
+    * new -m option for gbs changelog to add new entry
+    * create one entry in gbs changelog
+
+ -- Qiang Zhang <qiang.z.zhang@intel.com>  Wed, 27 Jun  2012 10:56:15 +0800
+
+gbs (0.7) unstable; urgency=high
+
+  * Add binfmt-support depend for arm build support
+  * print the detail path of binaries RPM packages
+
+ -- Qiang Zhang <qiang.z.zhang@intel.com>  Wed, 6 Jun  2012 10:56:15 +0800
+
+gbs (0.6.3) unstable; urgency=high
+
+  * Add binfmt-support depend for arm build support
+  * print the detail path of binaries RPM packages
+
+ -- Qiang Zhang <qiang.z.zhang@intel.com>  Mon, 4 Jun  2012 10:56:15 +0800
+
+gbs (0.6.2) unstable; urgency=high
+
+  * remove extra output information for gbs build
+  * dont need sudo before gbs build
+
+ -- Qiang Zhang <qiang.z.zhang@intel.com>  Fri, 1 Jun  2012 10:56:15 +0800
+
+gbs (0.6) unstable; urgency=high
+
+  * Upgrade to gbs v0.6, which contains the following features:
+    * subcommand renamed:
+      * build => remotebuild
+      * localbuild => build
+    * Update tizen*1.0.conf to fix build issue for tizen.org repo
+    * Code clean up:
+      * remove useless data/build.sh
+      * remove _fall_to_shell related code
+    * Add --ccache and --incremental options for gbs 'build'
+    * fix default build server api issue.
+    * fix git archive issue for zip format
+    * more error handling support
+
+ -- Qiang Zhang <qiang.z.zhang@intel.com>  Sat, 12 May 2012 10:56:15 +0800
+
+gbs (0.5) unstable; urgency=high
+
+  * Upgrade to gbs v0.5, which contains the following features:
+    * arm local build supported on ubuntu 10.04/10.10
+    * use sudo to run localbuild to fix proxy issue while using
+      tsocks. examples: $ sudo tsocks gbs localbuild
+    * fix permission issue while parsing specfile.
+
+ -- Qiang Zhang <qiang.z.zhang@intel.com>  Fri, 13 Apr 2012 10:56:15 +0800
+
+gbs (0.4) unstable; urgency=high
+
+  * Upgrade to gbs v0.4, which contains the following features:
+    * gbs localbuild/build: more archive tar ball format support
+    * unittest added:
+      * gbs help unit test
+      * utils/guess_version for tar ball unit test
+      * spec file parser module unit test
+    * Add arch check for gbs local build
+    * Raise obs error if Base project is empty
+
+ -- Qiang Zhang <qiang.z.zhang@intel.com>  Thu, 5 Apr 2012 10:56:15 +0800
+
+gbs (0.3) unstable; urgency=high
+
+  * Upgrade to gbs v0.3, which contains the following features:
+    * gbs localbuild support
+    * gbs import support, which support importing src.rpm and spec
+    * gbs import-orig support, which can used to update packages
+    * More information can be avaliable from 'man gbs'
+
+ -- Qiang Zhang <qiang.z.zhang@intel.com>  Fri, 2 Feb 2012 10:56:15 +0800
+
+gbs (0.2) unstable; urgency=high
+
+  * Update to latest stable release version 2.0.
+    * New gbs build: build rpm package from git repository on OBS
+    * New build service module to interact with OBS
+    * New git module to wrap local git command
+
+ -- Qiang Zhang <qiang.z.zhang@intel.com>  Fri, 2 Feb 2012 10:56:15 +0800
+
+gbs (0.1) unstable; urgency=high
+
+  * Initial release
+
+ -- Jian-feng Ding <jian-feng.ding@intel.com>  Fri, 2 Dec 2011 10:56:15 +0800
diff --git a/debian/compat b/debian/compat
new file mode 100644 (file)
index 0000000..7f8f011
--- /dev/null
@@ -0,0 +1 @@
+7
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..c5d207c
--- /dev/null
@@ -0,0 +1,22 @@
+Source: gbs
+Section: devel
+Priority: extra
+Maintainer: Jian-feng Ding <jian-feng.ding@intel.com>
+Build-Depends: debhelper (>= 7.0.15), python-dev
+Standards-Version: 3.8.0
+X-Python-Version: >= 2.7
+Homepage: http://www.tizen.org
+
+Package: gbs
+Architecture: all
+Depends: ${misc:Depends}, ${python:Depends},
+ python-pycurl,
+ git-core,
+ sudo,
+ osc (>= 0.136.0),
+ git-buildpackage-rpm (>= 0.6.0git20120822-tizen20121123),
+ depanneur (>= 0.3),
+ pristine-tar
+Description: The command line tools for Tizen package developers
+  The command line tools for Tizen package developers will
+  be used to do packaging related tasks.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..dfa1e65
--- /dev/null
@@ -0,0 +1,15 @@
+This work was packaged for Debian by:
+
+    Ding Jianfeng <jian-feng.ding@intel.com> on Fri, 02 Dec 2011 13:00:35 +0800
+
+It was downloaded from:
+
+    http://www.tizen.org
+
+Upstream Authors:
+
+    Intel Inc.
+
+Copyright:
+
+    Copyright (C) 2011 Intel Inc.
diff --git a/debian/docs b/debian/docs
new file mode 100644 (file)
index 0000000..a1320b1
--- /dev/null
@@ -0,0 +1 @@
+README.rst
diff --git a/debian/rules b/debian/rules
new file mode 100644 (file)
index 0000000..7e5ffc1
--- /dev/null
@@ -0,0 +1,49 @@
+#!/usr/bin/make -f
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+build: build-stamp
+build-stamp:
+       dh_testdir
+       python setup.py build
+
+clean:
+       dh_testdir
+       dh_testroot
+       rm -f build-stamp
+       dh_clean
+
+install: build
+       dh_testdir
+       dh_testroot
+       dh_clean -k
+       dh_installdirs
+       # Installing package
+       mkdir -p $(CURDIR)/debian/gbs $(CURDIR)/debian/gbs/usr/bin $(CURDIR)/debian/gbs/usr/share/doc/gbs
+       install -m644 docs/RELEASE_NOTES $(CURDIR)/debian/gbs/usr/share/doc/gbs
+       #make DESTDIR=$(CURDIR)/debian/gbs installman
+       #make DESTDIR=$(CURDIR)/debian/gbs installconf
+       #make DESTDIR=$(CURDIR)/debian/gbs installsymlinks
+       python setup.py install --root=$(CURDIR)/debian/gbs --prefix=/usr --install-layout=deb
+
+binary-indep: build install
+       dh_testdir
+       dh_testroot
+       dh_installchangelogs
+       dh_installdocs
+       dh_install
+       dh_installman
+       dh_link
+       dh_strip
+       dh_compress
+       dh_fixperms
+       dh_installdeb
+       dh_shlibdeps
+       dh_gencontrol
+       dh_md5sums
+       dh_builddeb
+
+binary-arch: build install
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install
diff --git a/distfiles/debian/compat b/distfiles/debian/compat
new file mode 100644 (file)
index 0000000..7f8f011
--- /dev/null
@@ -0,0 +1 @@
+7
diff --git a/distfiles/debian/control b/distfiles/debian/control
new file mode 100644 (file)
index 0000000..44ebf48
--- /dev/null
@@ -0,0 +1,23 @@
+Source: gbs
+Section: devel
+Priority: extra
+Maintainer: Jian-feng Ding <jian-feng.ding@intel.com>
+Build-Depends: debhelper (>= 7.0.15), python-dev
+Standards-Version: 3.8.0
+Homepage: http://www.tizen.org
+
+Package: gbs
+Architecture: all
+Depends: ${misc:Depends}, ${python:Depends},
+ git-core,
+ osc (>= 0.131),
+ build (>= 2011.10.10),
+ rpm,
+ qemu-arm-static (>= 0.14.1) | qemu-user-static,
+ binfmt-support,
+ sudo,
+ git-buildpackage-rpm,
+ python-pycurl
+Description: The command line tools for Tizen package developers
+  The command line tools for Tizen package developers will
+  be used to do packaging related tasks. 
diff --git a/distfiles/debian/copyright b/distfiles/debian/copyright
new file mode 100644 (file)
index 0000000..dfa1e65
--- /dev/null
@@ -0,0 +1,15 @@
+This work was packaged for Debian by:
+
+    Ding Jianfeng <jian-feng.ding@intel.com> on Fri, 02 Dec 2011 13:00:35 +0800
+
+It was downloaded from:
+
+    http://www.tizen.org
+
+Upstream Authors:
+
+    Intel Inc.
+
+Copyright:
+
+    Copyright (C) 2011 Intel Inc.
diff --git a/distfiles/debian/docs b/distfiles/debian/docs
new file mode 100644 (file)
index 0000000..a1320b1
--- /dev/null
@@ -0,0 +1 @@
+README.rst
diff --git a/distfiles/debian/rules b/distfiles/debian/rules
new file mode 100755 (executable)
index 0000000..f45ef94
--- /dev/null
@@ -0,0 +1,49 @@
+#!/usr/bin/make -f
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+build: build-stamp
+build-stamp:
+       dh_testdir
+       python setup.py build
+
+clean:
+       dh_testdir
+       dh_testroot
+       rm -f build-stamp
+       dh_clean
+
+install: build
+       dh_testdir
+       dh_testroot
+       dh_clean -k
+       dh_installdirs
+       # Installing package
+       mkdir -p $(CURDIR)/debian/gbs /usr/bin
+       #make DESTDIR=$(CURDIR)/debian/gbs installman
+       #make DESTDIR=$(CURDIR)/debian/gbs installconf
+       #make DESTDIR=$(CURDIR)/debian/gbs installsymlinks
+       python setup.py install --root=$(CURDIR)/debian/gbs --prefix=/usr --install-layout=deb
+
+binary-indep: build install
+       dh_testdir
+       dh_testroot
+       dh_installchangelogs
+       dh_installdocs
+       dh_install
+       dh_installman
+       dh_link
+       dh_strip
+       dh_compress
+       dh_fixperms
+       dh_installdeb
+       dh_shlibdeps
+       dh_gencontrol
+       dh_md5sums
+       dh_builddeb
+
+binary-arch: build install
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install
diff --git a/distfiles/gbs.conf b/distfiles/gbs.conf
new file mode 100644 (file)
index 0000000..7755326
--- /dev/null
@@ -0,0 +1,9 @@
+[general]
+; general settings
+tmpdir = /var/tmp
+
+[build]
+; settings for build subcommand
+build_server = https://api.tizen.org
+user = my_user_id
+passwd = pass_in_plaintxt
diff --git a/distfiles/gbs.dsc b/distfiles/gbs.dsc
new file mode 100644 (file)
index 0000000..2d5df86
--- /dev/null
@@ -0,0 +1,8 @@
+Format: 1.0
+Source: gbs
+Version: 0.9
+Binary: gbs
+Maintainer: Jian-feng Ding <jian-feng.ding@intel.com>
+Architecture: all
+Standards-Version: 3.7.1
+Build-Depends: debhelper (>= 4.0.0), python-dev
diff --git a/distfiles/gbs.spec b/distfiles/gbs.spec
new file mode 100644 (file)
index 0000000..5042f9f
--- /dev/null
@@ -0,0 +1,54 @@
+%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
+Name:       gbs
+Summary:    The command line tools for Tizen package developers
+Version:    0.12
+Release:    1
+Group:      Development/Tools
+License:    GPLv2
+BuildArch:  noarch
+URL:        http://www.tizen.org
+Source0:    %{name}_%{version}.tar.gz
+Requires:   python >= 2.7
+Requires:   python-pycurl
+Requires:   git-core
+Requires:   sudo
+Requires:   osc >= 0.136.0
+Requires:   tizen-gbp-rpm >= 20121123
+Requires:   depanneur >= 0.3
+Requires:   pristine-tar
+
+BuildRequires:  python-devel
+BuildRoot:  %{_tmppath}/%{name}-%{version}-build
+
+%description
+The command line tools for Tizen package developers will
+be used to do packaging related tasks. 
+
+
+%prep
+%setup -q -n %{name}-%{version}
+
+
+%build
+CFLAGS="$RPM_OPT_FLAGS" %{__python} setup.py build
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+%if 0%{?suse_version}
+%{__python} setup.py install --root=$RPM_BUILD_ROOT --prefix=%{_prefix}
+%else
+%{__python} setup.py install --root=$RPM_BUILD_ROOT -O1
+%endif
+
+#mkdir -p %{buildroot}/%{_prefix}/share/man/man1
+#install -m644 doc/gbs.1 %{buildroot}/%{_prefix}/share/man/man1
+
+%files
+%defattr(-,root,root,-)
+%doc README.rst docs/RELEASE_NOTES
+#%{_mandir}/man1/*
+%{python_sitelib}/*
+%dir %{_datadir}/%{name}
+%{_datadir}/%{name}/*
+%{_bindir}/*
diff --git a/docs/GBS.rst b/docs/GBS.rst
new file mode 100644 (file)
index 0000000..4e0159c
--- /dev/null
@@ -0,0 +1,1451 @@
+===
+GBS
+===
+
+----------------
+git build system
+----------------
+:Date:              2012-12-1
+:Copyright:         GPLv2
+:Version:           0.12
+:Manual section:    1
+:Manual group:      System
+
+Git Build System
+================
+
+**GBS**  (git-build-system) is a developer command line tool that supports Tizen package development. It's used to generate tarballs based on Git repositories, to do local test buildings, and to submit code to OBS (Tizen's main build service).
+
+This section contains more detailed GBS information. We recommend reading the `Setup Development Environment </documentation/developer-guide/environment-setup/>`_ pages first.
+
+- `Installation or Upgrade </documentation/developer-guide/environment-setup>`_:  How to install or upgrade the tools
+- `Configuration File </documentation/reference/git-build-system/configuration-file>`_:  How to modify the configuration for GBS
+- `Upstream package management </documentation/reference/git-build-system/upstream-tarball-and-patch-generation-support>`_:  Describes how to manage native and non-native packages in a more proper way
+- `GBS Usage </documentation/reference/git-build-system/usage>`_:  Describes, in more detail, how to use GBS
+- `FAQ </documentation/reference/git-build-system/faqs>`_:  Frequently Asked Questions
+
+Configuration File
+==================
+
+The configuration file contains all the configuration settings required by gbs. For example, build root and remote repo url for 'gbs build', remote OBS server for 'gbs remotebuild', etc.
+
+Configuration files used by GBS
+-------------------------------
+GBS will search for configuration files (.gbs.conf) within the folders below. If GBS finds multiple configuration files, it will load them in this order:
+
+- ``/etc/gbs.conf``         # for a global configuration, which exists in the package and which we suggest you don't change
+- ``~/.gbs.conf``           # for a user-specific configuration
+- ``$PWD/.gbs.conf``        # for a project/directory specific configuration
+
+Configuration values in a later file will override the values set in the previous ones.
+
+There is a global parameter `-c(--conf)` to specify the config file. If this option is used, GBS will load this config file and drop other config files in the default paths.
+
+If GBS can't find any config files, it will generate a config file into ~/.gbs.conf.
+
+Profile oriented style of configuration
+---------------------------------------
+A profile can contain many items for GBS build and remote build. There can be many profiles in one config file, such as one for Mobile, one for IVI, and so on.
+
+The default profile is defined in the [general] section. If you change the profile, all GBS behaviors could change.
+
+The mandatory rules for the section names are:
+
+
+- Profile section name should be started with `profile.`
+- OBS section name should started with `obs.`
+- Repository section name should started with `repo.`
+
+Common authentication info can be set in the profile level, no need to set them repeatedly in different obs and repo sections. If the authentication info is different for a different obs or repo, it can be set by the **user** and **passwd** key in the individual section.
+
+Example of a config file
+````````````````````````
+::
+
+  [general]
+  #Current profile name which should match a profile section name
+  profile = profile.tizen
+  buildroot = ~/GBS-ROOT/
+
+  [profile.tizen]
+  obs = obs.tizen
+  repos = repo.tizen_latest
+  # If no buildroot for profile, the buildroot in general section will be used
+  buildroot = ~/GBS-ROOT-profile.tizen/
+
+  [obs.tizen]
+  url = https://api.tizen.org
+  user = xxxx
+  passwd = xxxx
+  # set default base_prj for this obs
+  #base_prj=Tizen:Main
+  # set default target prj for this obs, default is home:<user>:gbs:<base_prj>
+  #target_prj=<specify target project>
+
+  [repo.tizen_latest]
+  url = http://download.tizen.org/releases/trunk/daily/ivi/latest/
+  #Optional user and password, set if differ from profile's user and password
+  #user =
+  #passwd =
+
+Configure repos for 'gbs build'
+```````````````````````````````
+
+Repos are configured as repo sections, and the section name must start with 'repo.' There are three types of keys supported for the repo section: url, user, and passwd.
+
+**Note**: When you specify the repo, please use the release folder, instead of the snapshot folder. The images/repos under the release folder are tested and released by release engineers. The images/repos under the snapshot folder are created by backend service automatically. Quality is not guaranteed.
+
+You can specify multiple repos in a profile.
+
+Here's an example:
+
+::
+
+  [profile.tizen]
+  repos = repo.tizen_latest, repo.my_local
+  
+  [repo.tizen_latest]
+  url = http://download.tizen.org/releases/trunk/daily/ivi/latest/
+  user = xxx
+  passwd = xxx
+  [repo.my_local]
+  #local repo must be an absolute path
+  url = /path/to/local/repo/
+
+**Note**: The local repo must be an absolute path. You don't need to run 'createrepo' for that local repo, a plain directory of RPM packages is enough.
+
+
+Configure build root for 'gbs build'
+````````````````````````````````````
+
+The default gbs build root is ~/GBS-ROOT/, but you can change it and set your own build root. gbs also supports setting different build root directories for different profiles, as follows:
+
+::
+
+  [profile.tizen]
+  obs = obs.tizen
+  repos = repo.tizen_latest
+  buildroot = ~/GBS-ROOT/
+
+**Note**: The plaintext password will be converted automatically as an encoded passwd, so after running gbs, the configuration will be changed as shown below. To change the password, you can delete 'passwdx' and set a new password for 'passwd':
+
+::
+
+  [obs.tizen]
+  url = https://api.tizen.org
+  user = xxxx
+  passwdx = QlpoOTFBWSZTWVyCeo8AAAKIAHJAIAAhhoGaAlNOLuSKcKEguQT1
+
+Configure multiple profiles
+```````````````````````````
+
+You can configure multiple profiles in one configuration file, for example, one profile for mobile, one profile for ivi, etc. For example, the 'profile' in the 'general' section is used to specify the default profile.
+
+::
+
+  [general]
+  profile = profile.ivi
+  
+  [profile.mobile]
+  ...
+  [profile.ivi]
+  ...
+
+Specify a profile in the command line
+`````````````````````````````````````
+
+Besides specifying the default profile in the configuration file, you can also specify it in the command line by using the `--profile/-P` option . You can specify the whole profile name, such as 'profile.ivi', or just specify the name without 'profile', such as 'ivi' in the case above. For example:
+
+::
+
+  $ gbs build --profile=profile.mobile -A i586
+  $ gbs remotebuild --profile=mobile -A i586   # given profile name without the "profile." prefix
+
+Specify a config file in the command line
+`````````````````````````````````````````
+
+The option `--config/-C` allows developers to specify one from multiple predefined configuration files. Once '-C' is specified, the default configuration will be skipped.
+
+Example for the command line:
+
+::
+
+  gbs -C ~/gbs-my.conf build -A ...
+
+
+Upstream tarball and patch-generation support
+=============================================
+
+This section describes how to manage packages more properly with GBS. "More properly" here meaning, if we (Tizen) are not the upstream of the package:
+
+- the source archive of the package (orig tarball) contains pristine upstream sources, not polluted with any local changes
+- local changes are presented as a series of patches, applied on top of the (pristine) orig archive
+
+Starting from version 0.11, GBS fully supports this package maintenance model.
+
+Native and non-native packages
+------------------------------
+
+General concepts
+````````````````
+
+From the package maintenance point of view, we can divide the packages into two categories:
+
+- **Native**:  packages where we/you/Tizen is the upstream and controls the source code repository. An example in the context of Tizen could be power-manager. For native packages, we control the versioning and releasing, so package maintenance is simpler. We can release a new version basically whenever we want.
+- **Non-native(or upstream)**: packages for which we/you/Tizen is not the upstream. For example, the Linux kernel or zlib. For these packages, we need to follow the releasing process and schedule of the upstream project. For example, from a developer and legal point of view, it is very beneficial to clearly track the local modifications (that is, separate upstream and local changes) both in the source code repository and on the packaging level.
+
+
+Also GBS divides packages into these two categories. GBS determines a package as non-native, if the git repository has an `upstream` branch. The actual name of the upstream branch can be configured using the 'upstream_branch' in option in the .gbs.conf file or with `--upstream-branch` command line option.
+
+GBS build, remotebuild, and export commands behave differently for native and non-native packages. Namely, the preparation of the packaging files for building differs.
+
+**GBS and native packages**
+
+GBS simply creates a monolithic source tarball from the HEAD of the current branch. Packaging files, from the packaging directory, are copied as is. No patch generation is done. This is the 'old' model GBS has used for all packages until now.
+
+**GBS and non-native packages**
+
+For non-native packages, GBS applies the new maintenance model. It tries to create a (real) upstream source tarball, generate patches from the local changes, and update the spec file accordingly.
+The logic is the following:
+
+- Generate patches
+
+  - Create patches between `upstream-tag..HEAD`, remove possible old patches
+  - Update the spec file: remove old 'Patch:' tags and '%patch' macros and replace them with ones that correspond with the newly generated patches.
+
+- Create upstream tarball if patch-generation was successful
+
+  - If the git repository has `pristine-tar` branch (and you have the pristine-tar tool installed), GBS tries to checkout the source tarball with pristine-tar
+  - If the previous step fails, GBS tries to create a source tarball from the correct `upstream tag`, matching the version taken from the .spec file.
+
+- If source tarball or patch generation fails GBS reverts back to the old method (that is, treats the package as native), creating just one monolithic tarball without patch generation.
+
+You shouldn't have any pre-existing patches in the packaging directory or spec file. Otherwise, GBS refuses to create patches. Please see `Advanced usage/Manually maintained patches` section for manually maintained patches.
+
+Building using upstream tarball and patch generation
+----------------------------------------------------
+
+This is pretty straightforward and easy to use. To enable upstream source tarball and patch generation you should:
+
+1. have `upstream branch` in the git repository, with untouched upstream sources
+
+2. have `upstream tag` format configured correctly in the package specific .gbs.conf, default is upstream/${upstreamversion}
+
+3. have your `development branch` be based on the upstream version (indicated in .spec)
+
+4. all your local manually maintained patches (in packaging dir) applied in to your development branch and removed from the packaging directory
+
+Additionally, you may have:
+
+5. `pristine-tar branch` in the git repository for generating the upstream tarball with the pristine-tar tool
+
+You can do development just like before. Just edit/commit/build on your development branch. GBS handles the tarball and patch generation, plus updating the spec file. Running gbs should look something like this (using gbs export as an example here for the shorted output):
+
+::
+
+ $ gbs export -o export
+ info: Generating patches from git (v1.2.7..HEAD)
+ info: Didn't find any old '%patch' macros, adding new patches after the last '%setup' macro at line %s
+ info: Didn't find any old 'Patch' tags, adding new patches after the last 'Source' tag.
+ info: zlib-1.2.7.tar.bz2 does not exist, creating from 'v1.2.7'
+ info: package files have been exported to:
+     /home/test/src/zlib/export/zlib-1.2.7-0
+
+When trying out the patch generation for the first time, you might want to export first and examine the auto-updated spec file (in the export directory) to see that GBS updated it correctly. Please see `Advanced usage/Manually maintained patches` section for manually maintained patches.
+
+Reasons for the upstream tarball and/or patch generation failure may be e.g.
+
+- upstream tag was not found
+
+  * version is not present in your git repository
+  * tag format is configured incorrectly
+
+- current branch is not a descendant of the upstream version that it claims to be derived from
+
+Managing upstream sources
+-------------------------
+
+This section is only of interest to the package maintainers.
+
+To maintain packages using the model described above, you need to keep unmodified upstream sources in a separate branch in your git repository.
+GBS supports two models for this.
+
+Import upstream source archive to git
+`````````````````````````````````````
+
+In this model, you import source tarballs (or zip files) from the upstream release to your git repository using the `gbs import` command.  GBS commits the sources in the upstream branch and creates a tag for the upstream release. An example of starting from scratch, that is importing to an empty repo:
+
+::
+
+ $ mkdir zlib && cd zlib && git init
+ $ gbs import ../zlib-1.2.6.tar.gz
+   ...
+ $ git branch
+ * master
+   upstream
+ $ git tag
+ upstream/1.2.6
+
+Now you could start development just by adding packaging files to the master branch. When you need to update to a newer upstream version, just use `gbs import` again:
+
+::
+
+ $ gbs import ../zlib-1.2.7.tar.gz
+ $ git tag
+ upstream/1.2.6
+ upstream/1.2.7
+
+**Note** Currently, GBS automatically merges the new upstream version to your master branch. Thus, you need to update the version number in your spec file accordingly.
+
+
+Tracking remote git
+```````````````````
+
+In this model, you directly track a remote (git) repository. You shouldn't use GBS import at all.
+GBS needs to know only the name of the upstream branch and the format of the upstream release tags.
+These are package dependent information so you should configure them in a package-specific .gbs.conf
+in the master branch. An example for starting a package from scratch, again:
+
+::
+
+ $ git clone git://github.com/madler/zlib.git && cd zlib
+ $ git branch -m master origin  # to keep origin tracking the upstream
+ $ git checkout -b master
+ $ vim .gbs.conf
+ $ git add .gbs.conf && git commit -m"Add gbs.conf"
+
+The example configuration file would be:
+
+::
+
+ [general]
+ upstream_branch = origin
+ upstream_tag = v${upstreamversion}
+
+Pristine-tar support
+````````````````````
+
+Optionally (but highly recommended!), you can use pristine-tar for storing/checking out the upstream tarballs (see http://joeyh.name/code/pristine-tar/). You can install it from the Tizen tools repository. Pristine-tar guarantees that the tarball generated by GBS is bit-identical to the real upstream release source tarball. GBS uses pristine-tar automatically if you have pristine-tar installed in your system. If you use GBS import to manage the upstream sources everything works out-of-the box: GBS import automatically commits new tarballs to the `pristine-tar branch`.
+
+However, if you track a remote upstream repository directly, you need to commit the upstream source tarballs to pristine-tar branch manually. So, like in our zlib example:
+
+::
+
+ $ cd zlib
+ $ git branch
+ * master
+   origin
+ $ pristine-tar commit ../zlib-1.2.7.tar.gz v1.2.7
+ $ git branch
+ * master
+   origin
+   pristine-tar
+
+Converting existing repository to the new model
+-----------------------------------------------
+
+1. You need an `upstream branch`
+
+  a. If you are already tracking the upstream, just configure the upstream branch name and tag format in the package-specific .gbp.conf.
+  b. If not, import upstream source tarball with `gbs import` or add the upstream remote to your repo and start tracking that.
+
+2. Recommended: If you're tracking the upstream git directly, you may want to do 'pristine-tar commit <tarball> <upstream-tag>'
+3. Rebase your current development branch on the correct upstream version (that is, rebase on the upstream tag)
+4. Remove all local patches: apply and commit them on top of your development branch and then remove the patches from the packaging directory and preferably from the spec file, too.
+
+
+Advanced usage
+--------------
+
+Manually maintained patches
+```````````````````````````
+
+GBS supports manually maintaining patches, that is, outside the automatic patch generation. This may be needed
+for architecture-dependent patches, for example, as GBS patch generation does not yet support conditional patches.
+Another example could be patches that are applied on top of a secondary source tree, whose sources are not maintained
+in your git tree, but only as a tarball in your packaging directory.
+
+To use this feature, you need to have your patch(es) in the packaging directory and listed in the spec.  In addition, you need to mark the patch to be ignored by the patch generation/importing by putting `# Gbp-Ignore-Patches: <patch numbers>` into the spec file. This will make GBS ignore the 'Patch:' tags and '%patch' macros of the listed patches when importing or generating patches.  An excerpt of an example spec file:
+
+::
+
+ ...
+ Source0:     %{name}-%{version}.tar.bz2
+ # Gbp-Ignore-Patches: 0
+ Patch0:     my.patch
+ %description
+ ...
+
+Actually, you can have this special marker anywhere in the spec file. And, it is case-insensitive, so you might use `GBP-IGNORE-PATCHES:`, for example, if you like it better. The reason for the GBP prefix is that GBS uses git-buildpackage (gbp) as the backend for patch generation.
+
+**Note:** In addition, pay attention to patch generation when building or exporting. Also `gbs import` will ignore patches
+marked for manual maintenance when importing source rpms.
+
+Patch macro location
+````````````````````
+
+
+GBS tries to automatically find the correct location to add the '%patch' macros in the spec file when updating it with the newly generated patches. This usually works fine, but GBS can also guess wrong. You can manually mark the location for auto-generated '%patch' macros by adding a `# Gbp-Patch-Macros` marker line into the spec file.  An excerpt of an example spec file:
+
+::
+
+ ...
+ %prep
+ %setup
+ # do things here...
+ # Gbp-Patch-Macros
+ # do more things here...
+ %build
+ ...
+
+GBS will put the new '%patch' macros after the marker line. This marker is case-insensitive, similar to `# Gbp-Ignore-Patches`.
+
+Squashing commits
+`````````````````
+
+When generating patches, GBS supports squashing a range of commits into one monolithic diff.
+Currently, one can only squash from `upstream-tag` up to a given commit-ish.
+An example use case could be squashing commits from an upstream release up to a stable update
+into a single diff (commits on top of the stable generate one patches normally).
+You can enable this with the 'squash_patches_until' config file option or with the
+'--squash-patches-until' command line option: the format for the option is <commit-ish>[:<filename-base>].
+
+An example:
+
+::
+
+ $ git branch
+ * master
+   stable
+   upstream
+ $ gbs export --squash-patches-until=stable:stable-update
+ info: Generating patches from git (upstream/0.1.2..HEAD)
+ info: Squashing commits a2a7d82..9c0f5ba into one monolithic 'stable-update.diff'
+ info: Didn't find any old 'Patch' tags, adding new patches after the last 'Source' tag.
+ info: Didn't find any old '%patch' macros, adding new patches after the last '%setup' macro
+ info: mypackage-0.1.2.tar.gz does not exist, creating from 'upstream/0.1.2'
+ info: package files have been exported to:
+      /home/user/src/mypackage/packaging/mypackage-0.1.2-1.21
+
+**Note!** If you're planning to use this, it is highly recommended that you configure it in the package-specific .gbs.conf file. This way, all users (including the automatic build machinery) build/export the package in a similar way.
+
+
+
+GBS Usage
+=========
+
+This section provides more details about GBS usage. You can also use `$ gbs --help` or `$ gbs <subcmd> --help` to get the help message.
+
+To get help:
+
+- For global options and the command list
+
+::
+
+  $ gbs  -h | --help
+
+- For each sub-command:
+
+::
+
+  $ gbs <sub-command> --help
+
+GBS provides several subcommands, including:
+
+
+- `gbs build  </documentation/reference/git-build-system/usage/gbs-build>`_: build rpm package from git repositories at the local development environment
+
+- `gbs remotebuild  </documentation/reference/git-build-system/usage/gbs-remotebuild>`_: generate tarballs based on Git repositories, and upload to remote OBS to build rpm packages
+
+- `gbs submit  </documentation/reference/git-build-system/usage/gbs-submit>`_: create/push annotate tag to Gerrit and trigger code submission to remote OBS
+
+- `gbs chroot  </documentation/reference/git-build-system/usage/gbs-chroot>`_: chroot to build root
+
+- `gbs import  </documentation/reference/git-build-system/usage/gbs-import/>`_: import source code to git repository, supporting these formats: source rpm, specfile, and tar ball
+
+- `gbs export  </documentation/reference/git-build-system/usage/gbs-export>`_: export files and prepare for building package, the spec file defines the format of tar ball
+
+- `gbs changelog  </documentation/reference/git-build-system/usage/gbs-changelog>`_: update the changelog file with git commits message
+
+GBS build
+---------
+
+By using 'gbs build', the developer can build the source code and generate rpm packages locally.
+For instructions on using the `build` subcommand, use this command: `gbs build --help`
+
+::
+
+ $ gbs build -h
+
+gbs build workflow
+``````````````````
+
+Input of gbs build
+''''''''''''''''''
+Below is the input for gbs build:
+
+- git project(s) which contains rpm packaging files
+- binary rpm repositories (remote or local)
+- project build configurations (macros, flags, etc)
+
+The binary rpm repositories contain all the binary rpm packages which are used to create the chroot environment and build packages, which can be remote, like tizen release or snapshot repositories, or local repository. Local repository supports two types:
+
+- Standard repository with repodata exists
+- A normal directory contains RPM packages. GBS will find all RPM packages under this directory.
+
+Please refer to `Configuration File </documentation/reference/git-build-system/configuration-file>`_ part to configure a repository.
+
+Build workflow
+''''''''''''''
+
+The input and output of gbs build are all repositories.
+
+**Note**: All the rpm packages under the output repository (by default, ~/GBS-ROOT/local/repos/<VERSION>/) will be used when building packages. That is, all the packages under the output repository will be applied to the build environment, so make sure the output repository is clean if you don't want this behavior.
+
+Here's the basic gbs build workflow
+
+::
+
+   ____________________
+  |                    |      ___________
+  | Source Code (GIT)  |---->|           |      _________________________
+  |____________________|     |           |     |                         |
+                             |           |     |  Local repository of    |
+   ____________________      | GBS Build |---->|  build RPM packages     |
+  |                    |     |           |     |(~/GBS-ROOT/local/repos/)|
+  |Binary repositories |     |           |     |_________________________|
+  |in GBS conf         |---->|___________|                  |
+  |(Remote or Local)   |           ^                        |
+  |____________________|           |________________________|
+
+
+From the above diagram, we can see the input and input are all repositories and the output repository located at '~/GBS-ROOT/locals/repos/' by default. You can change the repo path by using '--buildroot' to specify a different build root.
+
+Local repos in gbs build root ('~/GBS-ROOT' by default) will affect build results, so you must make sure that repos don't contains old or unnecessary RPM packages. While running gbs build, you can specify '--clean-repos' to clean up local repos, which gbs created, before building. We recommend that gbs users set different gbs build root directories for different profiles. There are several ways:
+
+- By default, the GBS build will put all output files under ~/GBS-ROOT/.
+- If the environment variable TIZEN_BUILD_ROOT exists, ${TIZEN_BUILD_ROOT} will be used as output top dir
+- If -B option is specified, then the specified directory is used, even if ${TIZEN_BUILD_ROOT} exists
+
+
+Output of gbs build
+'''''''''''''''''''
+
+Structure of a GBS build root directory
+
+::
+
+  gbs output top dir
+  |-- local
+  |   |-- cache                    # repodata and RPMs from remote repositories
+  |   |-- repos                    # generated local repo top directory
+  |   |   |-- tizen                # distro one: tizen
+  |   |   |   |-- armv7l           # store armv7l RPM packages
+  |   |   |   |-- i586             # store i586 RPM packages
+  |   |   `-- tizen2.0             # build for distro two: tizen2.0
+  |   |       `-- i586             # the same as above
+  |   |-- scratch.armv7l.0         # first build root for arm build
+  |   |-- scratch.i586.0           # second build root for i586 build
+  |   |-- scratch.i586.1           # third build root for i586 build
+  |   |-- scratch.i586.2           # fourth build root for i586 build
+  |   |-- scratch.i586.3           # fifth build root for i586 build
+  |   |-- scratch.i586.incremental # build root for incremental build
+  |   |                            # The above build root dir can be used by gbs chroot <build root dir>
+  |   `-- sources                  # sources generated for build, including tarball, spec, patches, etc.
+  |       |-- tizen
+  |       `-- tizen2.0
+  `-- meta                         # meta data used by gbs
+
+GBS Build Examples (Basic Usage)
+````````````````````````````````
+
+1. Build a single package.
+
+::
+
+   $ cd package1
+   $ gbs build -A ia32
+
+2. Build the package for a different architecture.
+
+::
+
+   $ gbs build -A armv7l      #build package for armv7l
+   $ gbs build -A i586        #build package for i586
+
+3. Make a clean build by deleting the old build root. This option must be specified if the repo has been changed, for example, changed to another release.
+
+::
+
+   $ gbs build -A armv7l --clean
+
+4. Build the package with a specific commit.
+
+::
+
+   $ gbs build -A armv7l --commit=<COMMIT_ID>
+
+5. Use `--overwrite` to trigger a rebuild.
+
+If you have already built before, and want to rebuild, `--overwrite` should be specified, or the packages will be skipped.
+
+::
+
+   $ gbs build -A ia32 --overwrite
+
+If you change the commit or specify `--include-all` option, it will always rebuild, so `--overwrite` is not needed.
+
+6. Output the debug info.
+
+::
+
+   $ gbs build -A ia32 --debug
+
+7. Build against a local repository. You can config the local repo at .gbs.conf file or through the command line.
+
+::
+
+   $ gbs build -R /path/to/repo/dir/ -A i586
+
+8. Use `--noinit` to build package in offline mode
+`--noinit` option can only be used if build root is ready. With `--noinit` option, gbs will not connect the remote repo, and skip parsing & checking repo and initialize build environment. `rpmbuild` will be used to build package directly. Here's an example:
+
+::
+
+  $ gbs build -A i586           # build first and create build environment
+  $ gbs build -A i586 --noinit  # use --noinit to start building directly
+
+9. Build with all uncommitted changes using `--include-all`.
+
+For example, there are one modified file and two extra files in the git tree:
+
+::
+
+   $ git status -s
+   M ail.pc.in
+   ?? base.repo
+   ?? main.repo
+
+- Build without the `--include-all` option
+
+Builds committed files only. All the modified files, which are not committed nor added, will NOT be built:
+
+::
+
+    $ gbs build -A ia32
+    warning: the following untracked files would NOT be included: base.repo main.repo
+    warning: the following uncommitted changes would NOT be included: ail.pc.in
+    warning: you can specify '--include-all' option to include these uncommitted and untracked files.
+    ....
+    info: Binaries RPM packages can be found here:
+    /home/test/GBS-ROOT/local/scratch.i686.0/home/abuild/rpmbuild/RPMS/
+    info: Done
+
+- Build with the `--include-all` option builds all the files:
+
+::
+
+    $ gbs build -A ia32 --include-all
+    info: the following untracked files would be included: base.repo main.repo
+    info: the following un-committed changes would be included: ail.pc.in
+    info: export tar ball and packaging files
+    ...
+    ...
+    [build finished]
+
+- Use .gitignore to ignore specific files, when using the `--include-all` option. If you want to ignore some files types, you can update your .gitignore. For example:
+
+::
+
+    $ cat .gitignore
+    .*
+    */.*
+    *.pyc
+    *.patch*
+
+
+
+Incremental build
+`````````````````
+
+Incremental Concept
+'''''''''''''''''''
+
+Starting from gbs 0.10, the gbs build subcommand supports building incrementally, which can be enabled by specifying the '--incremental' option.
+
+This mode is designed for development and verification of single packages. It is not intending to replace the standard mode. Only one package can be built at a time using this mode.
+
+This mode will set up the build environment in multiple steps, finishing by mounting the local Git tree of a package in the chroot build environment.
+
+**Note**: Because gbs will mount your git tree to the build root, be very careful when you remove your build root. You need to make sure you've already umounted the source tree manually before you remove it.
+
+This has the following benefits:
+
+1. The build environment uses the latest source code and changes to source do not trigger a new build environment (in the chroot).
+2. The Git source tree becomes the source of the builds.  Any change made in the Git repository followed by invocation of the build script will build the changed sources
+3. If the build fails for some reason, the build script will continue from the spot where it has failed, once the code has been changed to fix the problem causing the failure.
+
+This mode is, in many ways, similar to traditional code development, where changes are made to sources, followed by running `make` to test and compile the changes. However, it enables development using the build environment of the target, instead of the host OS.
+
+This method has some limitations, mostly related to packaging and how the sources are maintained.  Among others, it depends on how the RPM spec file is composed:
+
+1. It does not support patches in the spec file. All source has to be maintained as part of the Git tree
+2. It requires a clean packaging workflow.  Exotic workflows in the spec files might not work well, because this mode expects the following model:
+
+   a. Code preparation (%prep)
+   b. Code building (%build)
+   c. Code installation (%install)
+
+3. Because we run the %build section every time, if the %build script has configuration scripts (auto-tools), binaries might be regenerated, causing a complete build every time.  To avoid this, you are encouraged to use the following macros, which can be overridden using the `--no-configure` option:
+
+   a. %configure: runs the configure script with pre-defined paths and options.
+   b. %reconfigure: regenerates the scripts and runs %configure
+   c. %autogen: runs the autogen script
+
+
+Example
+'''''''
+
+In this example, we use `dlog` source code. First, we need to build with --incremental, then just modify one source file, and trigger the incremental build again. We will see that only modified source code has been compiled during the incremental build.
+
+::
+
+  $ cd dlog
+  # first build:
+  $ gbs build -A ia32 --incremental
+  $ vim log.c # change code
+  # second build:
+  $ gbs build -A ia32 --incremental
+  info: generate repositories ...
+  info: build conf has been downloaded at:
+  /var/tmp/test-gbs/tizen.conf
+  info: Start building packages from: /home/test/packages/dlog (git)
+  info: Prepare sources...
+  info: Retrieving repo metadata...
+  info: Parsing package data...
+  info: *** overwriting dlog-0.4.1-5.1 i586 ***
+  info: Next pass:
+  dlog
+  info: *** building dlog-0.4.1-5.1 i586 tizen (worker: 0) ***
+  info: Doing incremental build
+  [    0s] Memory limit set to 10854336KB
+  [    0s] Using BUILD_ROOT=/home/test/GBS-ROOT/local/scratch.i586.incremental
+  [    0s] Using BUILD_ARCH=i586:i686:noarch:
+  [    0s] test-desktop started "build dlog.spec" at Thu Sep 13 07:36:14 UTC 2012.
+  [    0s] -----------------------------------------------------------------
+  [    0s] ----- building dlog.spec (user abuild)
+  [    0s] -----------------------------------------------------------------
+  [    0s] -----------------------------------------------------------------
+  [    0s] + rpmbuild --short-circuit -bc /home/abuild/rpmbuild/SOURCES/dlog.spec
+  [    0s] Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.XLz8je
+  [    0s] + umask 022
+  [    0s] + export LD_AS_NEEDED
+  [    4s] + make -j4
+  [    4s] make  all-am
+  [    4s] make[1]: Entering directory /home/abuild/rpmbuild/BUILD/dlog-0.4.1
+  [    4s] /bin/sh ./libtool --tag=CC   --mode=compile gcc -c -o log.lo log.c
+  [    4s] mv -f .deps/log.Tpo .deps/log.Plo
+  [    4s] /bin/sh ./libtool --tag=CC --mode=link gcc -o libdlog.la /usr/lib log.lo
+  [    4s] libtool: link: gcc -shared  .libs/log.o -o .libs/libdlog.so.0.0.0
+  [    4s] libtool: link: ar cru .libs/libdlog.a  log.o
+  [    4s] libtool: link: ranlib .libs/libdlog.a
+  [    4s] make[1]: Leaving directory /home/abuild/rpmbuild/BUILD/dlog-0.4.1
+  [    4s] + exit 0
+  [    4s] finished "build dlog.spec" at Thu Sep 13 07:36:18 UTC 2012.
+  [    4s]
+  info: finished incremental building dlog
+  info: Local repo can be found here:
+  /home/test/GBS-ROOT/local/repos/tizen/
+  info: Done
+
+From the buildlog, we can see that only log.c has been re-compiled. That's the incremental build behavior.
+Currently limitation about incremental build
+
+`--noinit` option can be used together with `--incremental` to make build more quickly, like:
+
+::
+
+  $ gbs build --incremental --noinit
+
+
+
+Limitations of Incremental Build
+''''''''''''''''''''''''''''''''
+
+Incremental build don't support all packages. Here are some limitations:
+
+- Incremental build currently supports building only a single package. It doesn't support building multiple packages in parallel
+- The tarball's name in the spec file should be %{name}-%{version}.{tar.gz|tar.bz2|zip|...}, otherwise GBS can't mount source code to build the root correctly
+- %prep section should only contains %setup macro to unpack tar ball, and should not contains other source code related operations, such as unpack another source, apply patches, etc.
+
+
+Multiple packages build (dependency build)
+``````````````````````````````````````````
+
+Multiple package build has been supported since gbs 0.10. If packages have dependencies on each other, gbs will build packages in the correct order calculated by dependency relationship. Previously built out RPMs will be used to build the following packages that depend on them, which is the dependency build.
+
+**Examples**:
+
+1. Build all packages under a specified package directory
+
+::
+
+   $ mkdir tizen-packages
+   $ cp package1 package2 package3 ... tizen-packages/
+   $ gbs build -A ia32 tizen-packages # build all packages under tizen-packages
+
+2. Build multiple packages in parallel with `--threads`
+
+::
+
+   # current directory have multiple packages, --threads can be used to set the max build worker at the same time
+   $ gbs build -A armv7l --threads=4
+
+3. Select a group of packages to build
+
+`--binary-list` option can be used to specify a text file, which contains the RPM binary name list you want to build, the format is one package per line
+
+::
+
+$ gbs build -A ia32 --binary-list=/path/to/packages.list
+
+4. If you want to exclude some packages, `--exclude` can be used to exclude one package.
+
+::
+
+    $ gbs build -A ia32 tizen-packages --exclude=<pkg1>
+    $ gbs build -A ia32 tizen-packages --exclude=<pkg1> --exclude=<pkg2>
+
+5. If you want to exclude many packages, you can use `--exclude-from-file` to specify a package list. The format is the same as `--binary-list`
+
+::
+
+    $ gbs build -A ia32 tizen-packages --exclude-from-file=<file>
+
+
+
+Other useful options
+````````````````````
+
+Install extra packages to build root
+''''''''''''''''''''''''''''''''''''
+
+`--extra-packs=<pkgs list sep by comma>` can be used to install extra packages:
+
+::
+
+  $ gbs build --extra-packs=vim,zypper,gcc,gdb ...
+
+Keep all packages in build root
+'''''''''''''''''''''''''''''''
+
+Generally, `gbs build` will remove unnecessary packages in build root. While transferring to build another package, you can use `--keep-packs` to keep all unnecessary packages, and just install missing build required packages. This option can be used to speed up build multiple packages.
+
+::
+
+  $ gbs build --keep-packs
+
+`--keep-packs` can be used to create one build root for building multiple packages. Once the build root is ready, you can use --noinit to build these packages quickly.
+
+::
+
+$ gbs build pkg1/ --keep-packs -A i586
+$ gbs build pkg2/ --keep-packs -A i586
+$ gbs build pkg3/ --keep-packs -A i586
+
+Now, the build root (~/GBS-ROOT/local/scratch.i686.0) is ready for building pkg1, pkg2, and pkg3. You can use --noinit to build them offline, and don't need waste time to check repo updates and build root.
+
+::
+
+$ gbs build pkg1 --noinit
+$ gbs build pkg2 --noinit
+$ gbs build pkg3 --noinit
+
+
+Fetch the project build conf and customize build root (for Advanced Users)
+``````````````````````````````````````````````````````````````````````````
+
+Project build conf describes the project build configurations for the project, including pre-defined macros/packages/flags in the build environment. In Tizen releases, the build conf is released together with the released repo. You can find an example at: http://download.tizen.org/releases/daily/trunk/ivi/latest/builddata/xxx-build.conf
+
+- gbs build will fetch the build conf automatically
+
+Starting from gbs 0.7.1, by default, gbs will fetch the build conf from a remote repo, if you specify the remote Tizen repo, and then store it in your temp environment. Here's the build log:
+
+::
+
+    $ gbs build -A ia32
+    info: generate repositories ...
+    info: build conf has been downloaded at:
+    /var/tmp/<user>-gbs/tizen2.0.conf
+    info: generate tar ball: packaging/acpid-2.0.14.tar.bz2
+    [sudo] password for <user>:
+
+- build the package using your own project build conf, using the -D option
+
+
+You can save it and modify it, and then use it for your purposes:
+
+::
+
+ cp /var/tmp/<user>-gbs/tizen2.0.conf ~/tizen2.0.conf
+ $ gbs build -A ia32 -D ~/tizen2.0.conf
+
+If you need to customize the build config, refer to: http://en.opensuse.org/openSUSE:Build_Service_prjconf
+
+
+GBS remotebuild
+---------------
+
+Use the `remotebuild` subcommand to push local git code to the remote OBS build server
+to build. For instructions on using the `remotebuild` subcommand, use this command:
+
+::
+
+ $ gbs remotebuild --help
+
+Before running gbs remotebuild, you need to prepare a git repository package. The packaging directory must exist and have a spec file in it. GBS uses the package name, version, and source tarball format defined in this spec file.
+When it's ready, go to the top directory of git repository, and run gbs remotebuild, here's some examples
+
+::
+
+ $ gbs remotebuild
+ $ gbs remotebuild -B Tizen:Main
+ $ gbs remotebuild -B Tizen:Main -T home:<userid>:gbs
+ $ gbs remotebuild -B Tizen:Main --status
+ $ gbs remotebuild -B Tizen:Main --buildlog -R <repo> -A <arch>
+ $ gbs remotebuild -B Tizen:Main --include-all
+
+check build log and build status
+
+gbs supports the developer checking the build log and build status using the `--buildlog` and `--status` options during gbs remotebuild. For example:
+
+Step 1: Submit the changes to the remote OBS using `gbs remotebuild`. For example:
+
+Submit package to `home:user:gbs:Tizen:Main`, build against Tizen:Main
+
+::
+
+    test@test-desktop:~/ail$ gbs remotebuild -B Tizen:Main --include-all
+    info: Creating (native) source archive ail-0.2.29.tar.gz from 'c7309adbc60eae08782b51470c20aef6fdafccc0'
+    info: checking status of obs project: home:test:gbs:Tizen:Main ...
+    info: commit packaging files to build server ...
+    info: local changes submitted to build server successfully
+    info: follow the link to monitor the build progress:
+      https://build.tizendev.org/package/show?package=ail&project=home:test:gbs:Tizen:Main
+
+Step 2: Check the build status, example:
+
+::
+
+    # -B or -T options is needed if your target project is not home:user:gbs:Tizen:Main
+    test@test-desktop:~/ail$ gbs remotebuild --status
+    info: build results from build server:
+    standard       i586           building
+    standard       armv7el        building
+
+The first column is repo name and the second column is arch. repo/arch can be used to get buildlog.
+
+Step 3: Check the build log for special repo/arch
+
+::
+
+    test@test-desktop:~/ail$ gbs remotebuild --buildlog
+    error: please specify arch(-A) and repository(-R)
+    test@test-desktop:~/ail$ gbs remotebuild --buildlog -A i586 -R standard
+    info: build log for home:test:gbs:Tizen:Main/ail/standard/i586
+    ....
+
+
+GBS submit
+----------
+
+gbs submit can help the user create/push tags to gerrit, which would trigger pushing code from gerrit to OBS.
+You can get the usage of subcommand `submit` by:
+
+::
+
+ $ gbs submit --help
+
+
+Examples
+````````
+1) Create a tag on a current working branch and submit it directly.
+
+::
+
+  $ gbs submit -m 'release for 0.1'
+
+GBS would create an annotated tag named 'submit/${cur_branch_name}'/${date}.${time} on 'HEAD' commit, then submit it directly.
+
+2) Use `-c` option to submit specified commit
+
+::
+
+  $ gbs submit -c <commit_ID> -m 'release for 0.2'
+
+3) Use '--target' option to specify the target version to submit
+
+::
+
+  $ gbs submit --target=trunk -m 'release for 0.2.1'
+
+**Note**: `--target` allows the user to specify the target version. By default, it is 'trunk'. The valid value of `--target` should be matched with the remote branch name. The backend service would use this branch info to create the SR and submit it to the correct OBS project.
+
+4) use `-r` to specify remote gerrit server to submit. By default '-r' is 'origin'.
+
+::
+
+  $ gbs submit -r ssh://user@review.tizen.org:29418/public/base/gcc -m 'release for 0.4'
+
+5) If your gpg key has been set, you can use '-s' to create a signed tag.
+
+::
+
+  $ gbs submit -m 'release for 0.3' -s
+
+GBS chroot
+----------
+
+The subcommand 'chroot' allows users to chroot to the buildroot directory, which is generated by Â¡Â®gbs build¡¯. You can the basic usage of gbs chroot using:
+
+::
+
+  $ gbs chroot --help
+
+Note: The default location of the build root is located at: ~/GBS-ROOT/local/scratch.{arch}.*, which will be different if the -B option is specified while running gbs build
+
+Examples:
+
+- Chroot to i586 buildroot (the build root dir may be different in your host)
+
+::
+
+ $ gbs chroot ~/GBS-ROOT/local/scratch.i586.0/
+
+- Chroot as 'root' user
+
+::
+
+ $ gbs chroot -r ~/GBS-ROOT/local/scratch.i586.0/
+
+- Chroot and install more extra packages into buildroot directory for development purposes
+
+::
+
+  chroot as 'root':
+  $ gbs chroot -r ~/GBS-ROOT/local/scratch.i686.0/
+  Configure tizen repo in the chroot env:
+  # zypper ar http://user:passwd@download.tizen.org/releases/daily/<release_id>/repos/main/ia32/packages tizen-main
+  # zypper ar http://user:passwd@download.tizen.org/releases/daily/<release_id>/repos/base/ia32/packages tizen-base
+  Install extra packages, for example, install gdb.
+  # zypper refresh
+  # zypper -n install gdb gcc
+
+For https repositories, you need to specify 'ssl_verify=no'. For example:
+
+::
+
+  # zypper ar https://user:passwd@tizen.org/releases/daily/<release_id>/repos/main/ia32/packages/?ssl_verify=no tizen-main
+
+Notes:
+
+- If you want to use as 'root', you need specify '-r' option, then zypper can be used to install/remove packages
+- If you want to install packages in the build root env, you need specify the '-n' option, such as: zypper -n install gdb
+
+GBS import
+----------
+
+The subcommand will help to import source code into the git repository. Most of the time, it is used for initializing a git repository or for upgrading packages. It supports these formats: source rpm, specfile, and tar ball.
+
+For instructions on using the `import` subcommand, use this command: `gbs import --help`
+
+::
+
+$ gbs import --help
+
+Examples for running 'gbs import':
+
+Import from a source rpm
+````````````````````````
+
+::
+
+  $ gbs import sed-4.1.5-1/sed-4.1.5-1.src.rpm
+  info: No git repository found, creating one.
+  Initialized empty Git repository in /home/test/sed/.git/
+  info: Tag upstream/4.1.5 not found, importing Upstream upstream sources
+  info: Will create missing branch 'upstream'
+  pristine-tar: committed sed-4.1.5.tar.gz.delta to branch pristine-tar
+  info: Importing packaging files
+  info: Will create missing branch 'master'
+  info: Version '4.1.5-1' imported under 'sed'
+  info: done.
+  $ git tag
+  upstream/4.1.5
+  vendor/4.1.5-1
+  $ cd sed && git branch
+  * master
+    pristine-tar
+    upstream
+
+
+Import from spec file
+`````````````````````
+
+::
+
+  $ gbs import sed-4.1.5-1/sed-4.1.5-1.src.rpm
+  info: No git repository found, creating one.
+  Initialized empty Git repository in /home/test/sed/.git/
+  info: Tag upstream/4.1.5 not found, importing Upstream upstream sources
+  info: Will create missing branch 'upstream'
+  pristine-tar: committed sed-4.1.5.tar.gz.delta to branch pristine-tar
+  info: Importing packaging files
+  info: Will create missing branch 'master'
+  info: Version '4.1.5-1' imported under 'sed'
+  info: done.
+  $ cd sed && git branch
+  * master
+    pristine-tar
+    upstream
+  $ git tag
+  upstream/4.1.5
+  vendor/4.1.5-1
+
+If spec file contains patches, gbs will try to apply patches on top of master branch:
+
+::
+
+  $ cat sed-patch/sed.spec
+  ...
+  URL:        http://sed.sourceforge.net/
+  Source0:    ftp://ftp.gnu.org/pub/gnu/sed/sed-%{version}.tar.gz
+  Source1001: packaging/sed.manifest
+  Patch0:     0001-hello.patch
+  %description
+  ...
+  $ gbs import sed-patch/sed.spec
+  info: No git repository found, creating one.
+  Initialized empty Git repository in /home/test/sed/.git/
+  info: Tag upstream/4.1.5 not found, importing Upstream upstream sources
+  info: Will create missing branch 'upstream'
+  pristine-tar: committed sed-4.1.5.tar.gz.delta to branch pristine-tar
+  info: Importing packaging files
+  info: Will create missing branch 'master'
+  info: Importing patches to 'master' branch
+  info: Removing imported patch files from spec and packaging dir
+  info: Version '4.1.5-1' imported under 'sed'
+  info: done.
+  $ cd sed && git log --oneline
+  d94118f Autoremove imported patches from packaging
+  5d1333f hello
+  3a452d7 Imported vendor release 4.1.5-1
+  12104af Imported Upstream version 4.1.5
+  $ cat packaging/sed.spec
+  ...
+  URL:        http://sed.sourceforge.net/
+  Source0:    ftp://ftp.gnu.org/pub/gnu/sed/sed-%{version}.tar.gz
+  Source1001: packaging/sed.manifest
+  %description
+  ...
+
+
+Import a new tar ball
+`````````````````````
+
+Import tar ball can be used to upgrade a package. `gbs import` can only work if `upstream` branch exists. Here `upstream` branch can be defined in .gbs.conf or `--upstream-branch`. Once `gbs import` succeeded, new tar ball will be unpacked and import to `upstream` branch. If `pristine-tar` branch exists, tar ball is also be imported to pristine-tar branch.
+
+::
+
+  $ gbs import ../sed-4.2.0-1/sed-4.2.0.tar.gz
+  What is the upstream version? [4.2.0]
+  info: Importing '/home/test/sed-4.2.0-1/sed-4.2.0.tar.gz' to branch 'upstream'...
+  info: Source package is sed
+  info: Upstream version is 4.2.0
+  pristine-tar: committed sed-4.2.0.tar.gz.delta to branch pristine-tar
+  info: Successfully imported version 4.2.0 of /home/test/sed-4.2.0-1/sed-4.2.0.tar.gz
+  info: done.
+  test@test-desktop:~/sed$ git tag
+  upstream/4.1.5
+  upstream/4.2.0
+  $ git log --oneline
+   d3d25a7 Imported vendor release 4.1.5-1
+   1f6acaa Imported Upstream version 4.1.5
+  $ git checkout upstream && git log --oneline
+   Switched to branch 'upstream'
+   23220e6 Imported Upstream version 4.2.0
+   1f6acaa Imported Upstream version 4.1.5
+  $ git checkout pristine-tar && git log --oneline
+   Switched to branch 'pristine-tar'
+   7d44dad pristine-tar data for sed-4.2.0.tar.gz
+   71ee336 pristine-tar data for sed-4.1.5.tar.gz
+
+If you want to merge imported upstream branch to master automatically, `--merge` can be used:
+
+::
+
+  $ gbs import --merge ../sed-4.2.0-1/sed-4.2.0.tar.gz
+  What is the upstream version? [4.2.0]
+  info: Importing '/home/test/sed-4.2.0-1/sed-4.2.0.tar.gz' to branch 'upstream'...
+  info: Source package is sed
+  info: Upstream version is 4.2.0
+  pristine-tar: committed sed-4.2.0.tar.gz.delta to branch pristine-tar
+  info: Merging to 'master'
+  Merge made by recursive.
+  info: Successfully imported version 4.2.0 of /home/test/sed-4.2.0-1/sed-4.2.0.tar.gz
+  info: done.
+  $ git log --oneline
+   cc58b4c Merge commit 'upstream/4.2.0'
+   1f157c3 Imported Upstream version 4.2.0
+   482ef23 Imported vendor release 4.1.5-1
+   fc76416 Imported Upstream version 4.1.5
+
+
+GBS Export
+----------
+
+
+Use 'gbs export' to export git tree to tar ball and spec file.  You can see how to use the `export` subcommand by using this command:
+
+::
+
+ $ gbs export --help
+
+Examples:
+
+- export source code to default packaging directory
+
+::
+
+  $ gbs export
+  info: Generating patches from git (upstream/4.1.5..HEAD)
+  info: Didn't find any old 'Patch' tags, adding new patches after the last 'Source' tag.
+  info: Didn't find any old '%patch' macros, adding new patches after the last '%setup' macro
+  pristine-tar: successfully generated /var/tmp/.gbs_export_UJn0nS/sed-4.1.5.tar.gz
+  info: package files have been exported to:
+       /home/test/sed/packaging/sed-4.1.5-1
+  $ diff packaging/sed.spec packaging/sed-4.1.5-1/sed.spec
+  11a12,13
+  > # Patches auto-generated by git-buildpackage:
+  > Patch0:     0001-hello.patch
+  25a28,29
+  > # 0001-hello.patch
+  > %patch0 -p1
+
+
+From the log we can see patches has been generated, and tar ball is created from `pristine-tar` branch.
+
+
+- Use -o option to generate packaging files to specified path
+
+::
+
+ $ gbs export  -o ~/
+
+- Using `--source-rpm` option to generate source RPM package:
+
+
+::
+
+ $ gbs export  -o ~/ --source-rpm
+
+- Using `--spec` option, if there are multiple spec files
+
+::
+
+$ gbs export  --spec=dlog.spec
+
+`--spec` only accept file name should not contains any path info. gbs will prefix `packaging` dir automatically.
+
+
+GBS Changelog
+-------------
+
+
+Subcommand `changelog` is used to generate changelog file in ./packaging dir. It is mostly used for creating a changelog before submitting code.
+You can get the usage of subcommand `changelog` by using '$ gbs changelog --help'
+
+ $ gbs changelog --help
+
+Examples:
+
+::
+
+ test@test-desktop:~/acpid$ gbs ch --since=bed424ad5ddf74f907de0c19043e486f36e594b9
+ info: Change log has been updated.
+ test@test-desktop:~/acpid$ head packaging/acpid.changes
+ * Wed May 30 2012 xxxx <xxxx@example.com> 2.0.14@5c5f459
+ - cleanup specfile for packaging
+ * Wed May 30 2012 - xxxx <xxxx@example.com> - 2.0.10
+
+FAQ
+===
+
+This section contains frequently asked questions.
+
+Installation Related Issues
+---------------------------
+
+Q: I'm unable to get zypper to refresh from http://download.tizen.org/tools/openSUSE12.1/, but I'm not getting an error of repo issue
+
+A: This may be because there is a cached version at the proxy server. Try running the commands below to clean the cache:
+
+::
+
+ # clean the cache from proxy server or remote http server.
+ $ wget --no-cache http://download.tizen.org/tools/openSUSE12.1/repodata/repomd.xml
+ $ zypper refresh
+ $ zypper install gbs
+
+Q: I installed gbs from the official repo, but it is trying to use source code from /usr/local/lib/python*.
+
+A: This may be because you have installed gbs from source code before. Please remove the old gbs version.
+
+Q: How do I update GBS and its dependencies?
+
+A: GBS is open source software and it depends on several open source packages, including osc, git-core, build, rpm, etc. You should install all of these packages from the official GBS repo, especially the 'build' package. To update the 'build' package:
+
+- On Ubuntu: remove non-tizen repos, re-install 'build' package from Tizen repo
+
+::
+
+ $ dpkg -r --force-depends build
+ $ apt-get update
+ $ apt-get install build
+
+- On openSUSE:
+
+::
+
+ $ zypper refresh
+ $ zypper install tools:build # tools is the repo name for gbs repo
+
+gbs build Related Issues
+------------------------
+Q: How can I make my local repo have higher priority than the remote repo?
+
+A: It depends on the order of repos, the first repo will have the highest priority. In v0.10 and higher, GBS automatically puts local repos before remote repos.
+
+Q: 'gbs build' report build expansion error: nothing provides X needed by Y.
+
+A: The package you are trying to build is missing a dependency in the repo you specified. You may need to configure/add an additional repository. Try using the release repo, instead of the snapshot repo.
+
+Q: 'gbs build' exits unexpectedly when installing packages to create build root.
+
+A: This may be caused by a remote repo having been changed. You can specify `--clean` while running gbs build, like:
+
+::
+
+ $ gbs build -A <arch> --clean ...
+
+Q: 'gbs build' exits unexpectedly with errors: file XXXX from install of YYYYY conflicts with file from package ZZZZZ.
+
+A: This may be caused by a remote repo having been changed. You can specify `--clean` while running gbs build, like:
+
+::
+
+ $ gbs build -A <arch> --clean ...
+
+Q: 'gbs build' exits with errors: have choice for `XXXX` needed by packagename: package1 package2.
+
+A: This may be caused by a remote repo having two packages provide `XXXX`, and gbs don't know which one to use. In this case, you need download the build config and add one line like this:
+
+::
+
+ Prefer: package1
+
+or
+
+::
+
+ Prefer: package2
+
+To see how to download and customize build config, please refer to the gbs build usage page.
+
+Q: 'gbs build' fails to create an arm build env on Ubuntu 11.10
+
+A: This may be caused by qemu. 'qemu-user-static' has some issues with the Ubuntu official repo. Remove 'qemu-user-static' and install 'qemu-arm-static' from the Tizen tools repo.
+You can use this command:
+
+::
+
+ $ dpkg -r --force-depends qemu-user-static
+ $ apt-get update
+ $ apt-get install qemu-arm-static
+
+gbs Remote build Related Issues
+-------------------------------
+
+Q: I cannot access the remote build server (OBS) during a remote build
+
+A: This requires that you have an username and passwd and that you set them correctly in the configuration file. Also, make sure the build server api and proxy settings are correct for your environment.
+Proxy Related Issues
+
+Q: export no_proxy="localhost; 127.0.0.1; .company.com" does not work on Ubuntu
+
+A: Please set no_proxy as ".company.com" directly, and try again.
+
+Q: 'gbs build' returns '500 Can't connect to xxx'
+
+A: The proxy environment variable may have a trailing '/'. Remove the '/' from whatever is setting your environment variables and it should work. This is a known bug in the perl library. This issue is fixed in gbs 0.11.
+
+Q: 'gbs build' returns '500 SSL negotiation failed error'
+
+A: This is caused by the proxy server setting. The proxy you specified cannot forward SSL correctly. Try using another proxy.
+
+gbs chroot Related Issues
+-------------------------------
+
+Q: 'gbs chroot -r <build_root>' report error: 'su: user root does not exist'.
+
+A: This is caused by missing `login` package while creating build root. You can fix by updating /etc/passwd and /etc/group to add `root` user:
+
+::
+
+  $ echo "root:x:0:0:root:/root:/bin/bash" >>path/to/buildroot/etc/passwd
+  $ echo "root:x:0:" >>path/to/buildroot/etc/group
+
+Others
+------
+
+Q: [Fedora] gbs show error: "<user> is not in the sudoers file.  This incident will be reported".
+
+A: Update /etc/sudoers to give <user> sudo permission.
+
+Reporting issues
+================
+
+Please report bugs or feature requests at `JIRA <http://en.wikipedia.org/wiki/JIRA>`_: https://bugs.tizen.org.
+
+Detailed steps:
+
+- Click "create issue"
+- Select Projects: "Development Tools"
+- Select Components: "GBS"
+
+Source Code
+===========
+
+The source code is tracked at: https://github.com/01org/gbs
+
+
+License
+=======
+
+::
+
+ Copyright (c) 2012 Intel, Inc.
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the Free
+ Software Foundation; version 2 of the License
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ for more details.
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc., 59
+ Temple Place - Suite 330, Boston, MA 02111-1307, USA.
diff --git a/docs/RELEASE_NOTES b/docs/RELEASE_NOTES
new file mode 100644 (file)
index 0000000..1a146c0
--- /dev/null
@@ -0,0 +1,98 @@
+Release notes for gbs 0.12
+==========================
+
+- Release Date: 2012-12-13
+
+- 11 new features added:
+  1. --noinit support, just like offline mode of `osc build`
+  2. support building RPM package for incremental build
+  3. no need generate/unpack tarball for incremental build
+  4. support patch generation and upstream tarball create from upstream/pristine-tar branches.
+  5. x86_64 and armv6l support
+  6. add --keep-packs to keep unused packages in build root while building new packages.
+  7. show progress information when running remote build
+  8. support define macros from command line using --define option for rpmbuild
+  9. launch editor for 'gbs submit' if no -m specified, and you can input multiple lines of message.
+  10.enable importing patches while importing packages
+  11.show build progress for multiple packages build
+
+- 6 bug fixes included:
+  1. [remotebuiold] OBS empty response traceback for remotebuild
+  2. [remotebuiold] remove hardcode of default base project (-B), but you can still set default in gbs.conf
+  3. warning user and try again if umount failed for incremental build
+  4. request passwd again if one package build for a long time(>10 mins) on openSUSE
+  5. lock shared vars operations to avoid race condition
+  6. gbs remotebuild failed for link project if working package only exists in linked project.
+
+- 5 other changes:
+  1. add --merge option to replace --no-merge for gbs import, and not-merging is the default behavior
+  2. modify changelog order to follow default order of git log
+  3. show correct RPM/SRPM output directory for gbs build
+  4. give warning if build arch not compatible
+  5. add reST format document: docs/GBS.rst, which can be converted to html, man, and pdf formats.
+
+- Dependencies
+  - git-core
+  - python >= 2.7
+  - depanneur >= 0.3
+  - osc >= 0.136.0
+  - pristine-tar
+  - git-buildpackage
+
+Release notes for gbs 0.11
+==========================
+
+- Release Date: 2012-11-07
+
+- Four enhancements to the existing features:
+  1. add '-spec' option in 'gbs build' to support building package which
+     contains multiple spec files.
+  2. add '--profile/-P' option in 'gbs build' to support building packages by using specified
+    profile which defined in .gbs.conf
+  3. support configuring local buildroot directory in config file. The 'buildroot' can
+    be set under the 'general' section as a global setting.
+  4. better error report for 'gbs build', including gbs export
+    error, expansion error and rpmbuild error, etc.
+
+- 33 bug fixes included:
+  1. plaintext passwd printed for some error cases
+  2. gbs archive tar ball issue if using user defined macro in spec file
+  3. request passwd again if one package build for a long time(>15 mins)
+  4. sudo timeout issue, which will result in endless loop
+  5. return 0 from depanneur even if error occurs
+  6. unify display color of debug message in gbs and depanneur
+  7. endless loop if package circle dependency exists
+  8. gbs build error if '~' exist in build root path
+  9. passwd conflict issue with multiple instance of 'gbs build'
+  10. remotebuild can't run in sub-directory issue
+  11. gbs build error with https_proxy trailing '/'
+  12. gbs submit gives no error if there is no comment
+  13. describe missing dependencies for gbs build
+  14. support create project outside home:<user> if user have permission
+  15. server's certificate traceback issue for gbs remotebuild
+  16. traceback for remotebuild if OBS server return None
+  17. redundant error message of connection time out when no proxy
+  18. gbp will skip packaging when spec orig file format is not supported
+  19. gbs config override password error
+  20. gbs build --incremental doesn't support one package in a dir
+  21. GBS localbuild doesn't show debug info from the 'gbs export' command
+  22. [depanneur] gbs build --buildroot=~/buildroot can't expand character like ~
+  23. project name is not checked to be legal or not any more
+  24. remotebuild can't run in sub-directory
+  25. gbs duplicates qemu handling and emulation setup environment
+  26. gbs export:: misleading output message
+  27. package file export by gbs to wrong path
+  28. [gbp] gbp need increase / update its version for new gbs
+  29. Wrong default conf info for 'repo.*' in the .gbs.conf, should point to release repo
+  30. "_" is valid in package names, gbs import does not think so!
+  31. Typo in help message
+  32. getlogin fail issue on some system while running gbs build
+  33. --extra-packs option doesn't work with --ccache option
+
+- Dependencies
+  - git-core
+  - python >= 2.7
+  - depanneur >= 0.2
+  - osc >= 0.136.0
+  - pristine-tar
+  - git-buildpackage
diff --git a/gitbuildsys/__init__.py b/gitbuildsys/__init__.py
new file mode 100644 (file)
index 0000000..044343a
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""
+module for gbs tool
+"""
+
+__version__ = "0.12"
diff --git a/gitbuildsys/cmd_build.py b/gitbuildsys/cmd_build.py
new file mode 100644 (file)
index 0000000..2e86140
--- /dev/null
@@ -0,0 +1,343 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2012 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""Implementation of subcmd: localbuild
+"""
+
+import os
+import shutil
+import pwd
+import re
+
+from gitbuildsys import msger, utils, runner, errors
+from gitbuildsys.conf import configmgr
+from gitbuildsys.safe_url import SafeURL
+from gitbuildsys.cmd_export import transform_var_format_from_shell_to_python, \
+                                   get_packaging_dir
+
+from gbp.rpm.git import GitRepositoryError, RpmGitRepository
+
+CHANGE_PERSONALITY = {
+            'ia32':  'linux32',
+            'i686':  'linux32',
+            'i586':  'linux32',
+            'i386':  'linux32',
+            'ppc':   'powerpc32',
+            's390':  's390',
+            'sparc': 'linux32',
+            'sparcv8': 'linux32',
+          }
+
+BUILDARCHMAP = {
+            'ia32':     'i686',
+            'i586':     'i686',
+            'i386':     'i686',
+          }
+
+SUPPORTEDARCHS = [
+            'x86_64',
+            'ia32',
+            'i686',
+            'i586',
+            'i386',
+            'armv6l',
+            'armv7hl',
+            'armv7el',
+            'armv7tnhl',
+            'armv7nhl',
+            'armv7l',
+          ]
+
+# These two dicts maping come from osc/build.py
+CAN_ALSO_BUILD = {
+             'armv7l' :['armv4l', 'armv5l', 'armv6l', 'armv7l', 'armv5el', 'armv6el', 'armv7el'],
+             'armv7el':['armv4l', 'armv5l', 'armv6l', 'armv7l', 'armv5el', 'armv6el', 'armv7el'],
+             'armv8l' :['armv4l', 'armv5el', 'armv6el', 'armv7el', 'armv8el' ],
+             'i586'   :['i586', 'i386'],
+             'i686'   :['i686', 'i586', 'i386',],
+             'x86_64' :['x86_64', 'i686', 'i586', 'i386'],
+            }
+
+QEMU_CAN_BUILD = [ 'armv4l', 'armv5el', 'armv5l', 'armv6l', 'armv7l', 'armv6el', 'armv7el', 'armv7hl', 'armv8el',
+                   'sh4', 'mips', 'mipsel',
+                   'ppc', 'ppc64',
+                   's390', 's390x',
+                   'sparc64v', 'sparcv9v', 'sparcv9', 'sparcv8', 'sparc',
+                   'hppa'
+                ]
+
+USERID = pwd.getpwuid(os.getuid())[0]
+TMPDIR = os.path.join(configmgr.get('tmpdir', 'general'), '%s-gbs' % USERID)
+
+def prepare_repos_and_build_conf(args, arch, profile):
+    '''generate repos and build conf options for depanneur'''
+
+    cmd_opts = []
+    cache = utils.Temp(prefix=os.path.join(TMPDIR, 'gbscache'),
+                       directory=True)
+    cachedir  = cache.path
+    if not os.path.exists(cachedir):
+        os.makedirs(cachedir)
+    msger.info('generate repositories ...')
+
+    if args.skip_conf_repos:
+        repos = []
+    else:
+        repos = [i.url for i in profile.repos]
+
+    if args.repositories:
+        for i in args.repositories:
+            try:
+                opt_repo = SafeURL(i)
+            except ValueError, err:
+                msger.warning('Invalid repo %s: %s' % (i, str(err)))
+            else:
+                repos.append(opt_repo)
+
+    if not repos:
+        msger.error('No package repository specified.')
+
+    repoparser = utils.RepoParser(repos, cachedir)
+    repourls = repoparser.get_repos_by_arch(arch)
+    if not repourls:
+        msger.error('no available repositories found for arch %s under the '
+                    'following repos:\n%s' % (arch, '\n'.join(repos)))
+    cmd_opts += [('--repository=%s' % url.full) for url in repourls]
+
+    if args.dist:
+        distconf = args.dist
+        if not os.path.exists(distconf):
+            msger.error('specified build conf %s does not exists' % distconf)
+    else:
+        if repoparser.buildconf is None:
+            msger.error('failed to get build conf from repos, please '
+                        'use snapshot repo or specify build config using '
+                        '-D option')
+        else:
+            shutil.copy(repoparser.buildconf, TMPDIR)
+            distconf = os.path.join(TMPDIR, os.path.basename(\
+                                    repoparser.buildconf))
+            msger.info('build conf has been downloaded at:\n      %s' \
+                       % distconf)
+
+    if distconf is None:
+        msger.error('No build config file specified, please specify in '\
+                    '~/.gbs.conf or command line using -D')
+
+    # must use abspath here, because build command will also use this path
+    distconf = os.path.abspath(distconf)
+
+    if not distconf.endswith('.conf') or '-' in os.path.basename(distconf):
+        msger.error("build config file must end with .conf, and can't "
+                    "contain '-'")
+    dist = os.path.basename(distconf)[:-len('.conf')]
+    cmd_opts += ['--dist=%s' % dist]
+    cmd_opts += ['--configdir=%s' % os.path.dirname(distconf)]
+
+    return cmd_opts
+
+def prepare_depanneur_opts(args):
+    '''generate extra options for depanneur'''
+
+    cmd_opts = []
+    if args.exclude:
+        cmd_opts += ['--exclude=%s' % i for i in args.exclude]
+    if args.exclude_from_file:
+        cmd_opts += ['--exclude-from-file=%s' % args.exclude_from_file]
+    if args.overwrite:
+        cmd_opts += ['--overwrite']
+    if args.clean_once:
+        cmd_opts += ['--clean-once']
+    if args.clean_repos:
+        cmd_opts += ['--clean-repos']
+    if args.debug:
+        cmd_opts += ['--debug']
+    if args.incremental:
+        cmd_opts += ['--incremental']
+    if args.keepgoing:
+        cmd_opts += ['--keepgoing']
+    if args.no_configure:
+        cmd_opts += ['--no-configure']
+    if args.keep_packs:
+        cmd_opts += ['--keep-packs']
+    if args.binary_list:
+        if not os.path.exists(args.binary_list):
+            msger.error('specified binary list file %s not exists' %\
+                        args.binary_list)
+        cmd_opts += ['--binary=%s' % args.binary_list]
+    cmd_opts += ['--threads=%s' % args.threads]
+    cmd_opts += ['--packaging-dir=%s' % get_packaging_dir(args)]
+
+    return cmd_opts
+
+def get_processors():
+    """
+    get number of processors (online) based on
+    SC_NPROCESSORS_ONLN (returns 1 if config name does not exist).
+    """
+    try:
+        return os.sysconf('SC_NPROCESSORS_ONLN')
+    except ValueError:
+        return 1
+
+def find_binary_path(binary):
+    """
+    return full path of specified binary file
+    """
+    if os.environ.has_key("PATH"):
+        paths = os.environ["PATH"].split(":")
+    else:
+        paths = []
+        if os.environ.has_key("HOME"):
+            paths += [os.environ["HOME"] + "/bin"]
+        paths += ["/usr/local/sbin", "/usr/local/bin", "/usr/sbin",
+                  "/usr/bin", "/sbin", "/bin"]
+
+    for path in paths:
+        bin_path = "%s/%s" % (path, binary)
+        if os.path.exists(bin_path):
+            return bin_path
+    return None
+
+def is_statically_linked(binary):
+    """
+    check if binary is statically linked
+    """
+    return ", statically linked, " in runner.outs(['file', binary])
+
+def get_profile(args):
+    """
+    Get the build profile to be used
+    """
+    if args.profile:
+        profile_name = args.profile if args.profile.startswith("profile.") \
+                                    else "profile." + args.profile
+        profile = configmgr.build_profile_by_name(profile_name)
+    else:
+        profile = configmgr.get_current_profile()
+    return profile
+
+
+def main(args):
+    """gbs build entry point."""
+
+    if args.commit and args.include_all:
+        raise errors.Usage('--commit can\'t be specified together with '\
+                           '--include-all')
+    if args.noinit and (args.clean or args.clean_once):
+        raise errors.Usage('--noinit can\'t be specified together with '\
+                           '--clean or --clean-once')
+    workdir = args.gitdir
+
+    try:
+        repo = RpmGitRepository(workdir)
+        workdir = repo.path
+    except GitRepositoryError:
+        if args.spec:
+            msger.error("git project can't be found for --spec, "
+                        "give it in argument or cd into it")
+
+    hostarch = os.uname()[4]
+    if args.arch:
+        buildarch = args.arch
+    else:
+        buildarch = hostarch
+        msger.info('No arch specified, using system arch: %s' % hostarch)
+
+    if not buildarch in SUPPORTEDARCHS:
+        msger.error('arch %s not supported, supported archs are: %s ' % \
+                   (buildarch, ','.join(SUPPORTEDARCHS)))
+
+    if buildarch in BUILDARCHMAP:
+        buildarch = BUILDARCHMAP[buildarch]
+
+    if buildarch not in CAN_ALSO_BUILD.get(hostarch, []):
+        if buildarch not in QEMU_CAN_BUILD:
+            msger.error('hostarch: %s can\'t build target arch %s' % \
+                       (hostarch, buildarch))
+
+    profile = get_profile(args)
+    if args.buildroot:
+        build_root = args.buildroot
+    elif 'TIZEN_BUILD_ROOT' in os.environ:
+        build_root = os.environ['TIZEN_BUILD_ROOT']
+    elif profile.buildroot:
+        build_root = profile.buildroot
+    else:
+        build_root = configmgr.get('buildroot', 'general')
+    build_root = os.path.expanduser(build_root)
+    build_root = transform_var_format_from_shell_to_python(build_root)
+    sanitized_profile_name = re.sub("[^a-zA-Z0-9:._-]", "_", profile.name)
+    build_root = build_root % {'tmpdir': TMPDIR,
+                               'profile': sanitized_profile_name}
+    os.environ['TIZEN_BUILD_ROOT'] = os.path.abspath(build_root)
+
+    # get virtual env from system env first
+    if 'VIRTUAL_ENV' in os.environ:
+        cmd = ['%s/usr/bin/depanneur' % os.environ['VIRTUAL_ENV']]
+    else:
+        cmd = ['depanneur']
+
+    cmd += ['--arch=%s' % buildarch]
+
+    if args.clean:
+        cmd += ['--clean']
+
+    # check & prepare repos and build conf
+    if not args.noinit:
+        cmd += prepare_repos_and_build_conf(args, buildarch, profile)
+    else:
+        cmd += ['--noinit']
+
+    cmd += ['--path=%s' % workdir]
+
+    if args.ccache:
+        cmd += ['--ccache']
+
+    if args.extra_packs:
+        cmd += ['--extra-packs=%s' % args.extra_packs]
+
+    if hostarch != buildarch and buildarch in CHANGE_PERSONALITY:
+        cmd = [ CHANGE_PERSONALITY[buildarch] ] + cmd
+
+    # Extra depanneur special command options
+    cmd += prepare_depanneur_opts(args)
+
+    # Extra options for gbs export
+    if args.include_all:
+        cmd += ['--include-all']
+    if args.commit:
+        cmd += ['--commit=%s' % args.commit]
+    if args.upstream_branch:
+        cmd += ['--upstream-branch=%s' % args.upstream_branch]
+    if args.upstream_tag:
+        cmd += ['--upstream-tag=%s' % args.upstream_tag]
+    if args.squash_patches_until:
+        cmd += ['--squash-patches-until=%s' % args.squash_patches_until]
+
+    if args.define:
+        cmd += [('--define="%s"' % i) for i in args.define]
+    if args.spec:
+        cmd += ['--spec=%s' % args.spec]
+
+    msger.debug("running command: %s" % ' '.join(cmd))
+    retcode = os.system(' '.join(cmd))
+    if retcode != 0:
+        msger.error('rpmbuild fails')
+    else:
+        msger.info('Done')
diff --git a/gitbuildsys/cmd_changelog.py b/gitbuildsys/cmd_changelog.py
new file mode 100644 (file)
index 0000000..418fb85
--- /dev/null
@@ -0,0 +1,145 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2012 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""Implementation of subcmd: changelog
+"""
+
+import os
+import datetime
+import glob
+
+from gitbuildsys import msger
+from gitbuildsys.utils import guess_spec, edit_file
+from gitbuildsys.cmd_export import get_packaging_dir
+
+from gbp.rpm.git import GitRepositoryError, RpmGitRepository
+
+
+
+def get_all_entries(changesfile, new_entries):
+    """return all entries including old in changesfile and new_entries"""
+    lines = ["%s%s" % (line, os.linesep) for line in new_entries]
+    lines.append(os.linesep)
+
+    if os.path.exists(changesfile):
+        with open(changesfile) as chlog:
+            lines.extend(chlog.readlines())
+    return ''.join(lines)
+
+
+def get_latest_rev(changesfile):
+    """Get latest git revision from the changelog."""
+    if os.path.exists(changesfile):
+        with open(changesfile) as chlog:
+            line = chlog.readline()
+            return line.strip().split(" ")[-1].split("@")[-1]
+    return ''
+
+def get_version(git_repo, commit):
+    """
+    Construct version from commit using rev-parse.
+    Set version to <tag>@<sha1> or <sha1> if tag is not found.
+    """
+    version = git_repo.rev_parse(commit, short=7)
+    try:
+        version = "%s@%s" % (git_repo.find_tag(commit), version)
+    except GitRepositoryError:
+        pass
+
+    return version
+
+def make_log_entries(commits, git_repo):
+    """Make changelog entries from the set of git commits."""
+    entries = []
+    # Add header
+    author = git_repo.get_author_info()
+    entries.append("* %s %s <%s> %s" % \
+                   (datetime.datetime.now().strftime("%a %b %d %Y"),
+                    author.name, author.email, get_version(git_repo,
+                                                           commits[0])))
+    for commit in commits:
+        commit_info =  git_repo.get_commit_info(commit)
+        entries.append("- %s" % commit_info["subject"])
+    return entries
+
+
+def main(args):
+    """gbs changelog entry point."""
+
+    try:
+        repo = RpmGitRepository(args.gitdir)
+    except GitRepositoryError, err:
+        msger.error(str(err))
+
+    project_root_dir = repo.path
+
+    packaging_dir = get_packaging_dir(args)
+    changes_file_list = glob.glob("%s/%s/*.changes" % (project_root_dir,
+                                                       packaging_dir))
+
+    if args.spec or not changes_file_list:
+        # Create .changes file with the same name as a spec
+        specfile = os.path.basename(guess_spec(project_root_dir,
+                                               packaging_dir, args.spec))
+        fn_changes = os.path.splitext(specfile)[0] + ".changes"
+        fn_changes = os.path.join(project_root_dir, packaging_dir, fn_changes)
+    else:
+        fn_changes = changes_file_list[0]
+        if len(changes_file_list) > 1:
+            msger.warning("Found more than one changes files, %s is taken " \
+                           % (changes_file_list[0]))
+
+    # get the commit start from the args.since
+    if args.since:
+        since = args.since
+    else:
+        since = get_latest_rev(fn_changes)
+
+    commitid_since = None
+    if since:
+        try:
+            commitid_since = repo.rev_parse(since)
+        except GitRepositoryError:
+            if args.since:
+                msger.error("Invalid commit: %s" % (since))
+            else:
+                msger.error("Can't find last commit ID in the log, "\
+                            "please specify it by '--since'")
+
+    commits = repo.get_commits(commitid_since, 'HEAD')
+    if not commits:
+        msger.error("Nothing found between %s and HEAD" % commitid_since)
+
+    if args.message:
+        author = repo.get_author_info()
+        lines = ["- %s" % line for line in args.message.split(os.linesep) \
+                                            if line.strip()]
+        new_entries = ["* %s %s <%s> %s" % \
+                           (datetime.datetime.now().strftime("%a %b %d %Y"),
+                            author.name, author.email,
+                            get_version(repo, commits[0]))]
+        new_entries.extend(lines)
+    else:
+        new_entries = make_log_entries(commits, repo)
+
+    content = get_all_entries(fn_changes, new_entries)
+    if edit_file(fn_changes, content):
+        msger.info("Change log has been updated.")
+    else:
+        msger.info("Change log has not been updated")
+
diff --git a/gitbuildsys/cmd_chroot.py b/gitbuildsys/cmd_chroot.py
new file mode 100644 (file)
index 0000000..c126e8f
--- /dev/null
@@ -0,0 +1,54 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2012 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""Implementation of subcmd: chroot
+"""
+import os
+import subprocess
+
+from gitbuildsys import msger
+
+def main(args):
+    """gbs chroot entry point."""
+
+    build_root = args.buildroot
+
+    running_lock = '%s/not-ready' % build_root
+    if os.path.exists(running_lock):
+        msger.error('build root %s is not ready' % build_root)
+
+    msger.info('chroot %s' % build_root)
+    user = 'abuild'
+    if args.root:
+        user = 'root'
+    cmd = ['sudo', 'chroot', build_root, 'su', user]
+
+    try:
+        subprocess.call(['sudo', 'cp', '/etc/resolv.conf', build_root + \
+                         '/etc/resolv.conf'])
+    except OSError:
+        msger.warning('failed to setup /etc/resolv.conf')
+
+    try:
+        build_env = os.environ
+        build_env['PS1'] = "(tizen-build-env)@\h \W]\$ "
+        subprocess.call(cmd, env=build_env)
+    except OSError, err:
+        msger.error('failed to chroot to %s: %s' % (build_root, err))
+    except KeyboardInterrupt:
+        msger.info('keyboard interrupt ...')
diff --git a/gitbuildsys/cmd_export.py b/gitbuildsys/cmd_export.py
new file mode 100644 (file)
index 0000000..2156c54
--- /dev/null
@@ -0,0 +1,281 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2012 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""Implementation of subcmd: export
+"""
+
+import os
+import re
+import shutil
+import errno
+from urlparse import urlparse
+
+from gitbuildsys import msger, utils, errors
+from gitbuildsys.conf import configmgr
+
+from gbp.scripts.buildpackage_rpm import main as gbp_build
+from gbp.rpm.git import GitRepositoryError, RpmGitRepository
+import gbp.rpm as rpm
+from gbp.errors import GbpError
+
+
+def mkdir_p(path):
+    """
+    Create directory as in mkdir -p
+    """
+    try:
+        os.makedirs(path)
+    except OSError as exc: # Python >2.5
+        if exc.errno == errno.EEXIST:
+            pass
+        else:
+            raise
+
+def is_native_pkg(repo, args):
+    """
+    Determine if the package is "native"
+    """
+    if args.upstream_branch:
+        upstream_branch = args.upstream_branch
+    else:
+        upstream_branch = configmgr.get('upstream_branch', 'general')
+    return not repo.has_branch(upstream_branch)
+
+def get_packaging_dir(args):
+    """
+    Determine the packaging dir to be used
+    """
+    if args.packaging_dir:
+        path = args.packaging_dir
+    else:
+        path = configmgr.get('packaging_dir', 'general')
+    return path.rstrip(os.sep)
+
+def transform_var_format_from_shell_to_python(whole):
+    '''replace string like ${xxx} with %(xxx)s'''
+    return re.sub(r'\$\{([^}]+)\}', r'%(\1)s', whole)
+
+def check_export_branches(repo, args):
+    '''checking export related branches: pristine-tar, upstream.
+    give warning if pristine-tar/upstream branch exist in remote
+    but have not been checkout to local
+    '''
+    remote_branches = [branch.split('/')[-1] for branch in \
+                       repo.get_remote_branches()]
+    if args.upstream_branch:
+        upstream_branch = args.upstream_branch
+    else:
+        upstream_branch = configmgr.get('upstream_branch', 'general')
+
+    # upstream exist, but pristine-tar not exist
+    if repo.has_branch(upstream_branch) and \
+       not repo.has_branch('pristine-tar') and \
+       'pristine-tar' in remote_branches:
+        msger.warning('pristine-tar branch exist in remote branches, '
+                      'you can checkout it to enable exporting upstrean '
+                      'tarball from pristine-tar branch')
+
+    # all upstream and pristine-tar are not exist
+    if not repo.has_branch(upstream_branch) and \
+       not repo.has_branch('pristine-tar') and  \
+       'pristine-tar' in remote_branches and upstream_branch in remote_branches:
+        msger.warning('pristine-tar and %s branches exist in remote branches, '
+                      'you can checkout them to enable upstream tarball and '
+                      'patch-generation ' % upstream_branch)
+
+def create_gbp_export_args(repo, commit, export_dir, tmp_dir, spec, args,
+                           force_native=False):
+    """
+    Construct the cmdline argument list for git-buildpackage export
+    """
+    if args.upstream_branch:
+        upstream_branch = args.upstream_branch
+    else:
+        upstream_branch = configmgr.get('upstream_branch', 'general')
+    if args.upstream_tag:
+        upstream_tag = args.upstream_tag
+    else:
+        upstream_tag = configmgr.get('upstream_tag', 'general')
+        upstream_tag = transform_var_format_from_shell_to_python(upstream_tag)
+    msger.debug("Using upstream branch: %s" % upstream_branch)
+    msger.debug("Using upstream tag format: '%s'" % upstream_tag)
+
+    # Get patch squashing option
+    if args.squash_patches_until:
+        squash_patches_until = args.squash_patches_until
+    else:
+        squash_patches_until = configmgr.get('squash_patches_until', 'general')
+
+    # Determine the remote repourl
+    reponame = ""
+    remotes = repo.get_remote_repos()
+    if remotes:
+        remotename = 'origin' if 'origin' in remotes else remotes.keys()[0]
+        # Take the remote repo of current branch, if available
+        try:
+            remote_branch = repo.get_upstream_branch(repo.branch)
+            if remote_branch:
+                remotename = remote_branch.split("/")[0]
+        except GitRepositoryError:
+            pass
+        reponame = urlparse(remotes[remotename][0]).path.lstrip('/')
+
+    packaging_dir = get_packaging_dir(args)
+    # Now, start constructing the argument list
+    argv = ["argv[0] placeholder",
+            "--git-color-scheme=magenta:green:yellow:red",
+            "--git-ignore-new",
+            "--git-upstream-branch=upstream",
+            "--git-export-dir=%s" % export_dir,
+            "--git-tmp-dir=%s" % tmp_dir,
+            "--git-packaging-dir=%s" % packaging_dir,
+            "--git-spec-file=%s" % spec,
+            "--git-export=%s" % commit,
+            "--git-upstream-branch=%s" % upstream_branch,
+            "--git-upstream-tag=%s" % upstream_tag,
+            "--git-spec-vcs-tag=%s#%%(tagname)s" % reponame]
+
+    if force_native or is_native_pkg(repo, args):
+        argv.extend(["--git-no-patch-export",
+                     "--git-upstream-tree=%s" % commit])
+    else:
+        argv.extend(["--git-patch-export",
+                     "--git-patch-export-compress=100k",
+                     "--git-force-create",
+                     "--git-patch-export-squash-until=%s" %
+                        squash_patches_until,
+                     "--git-patch-export-ignore-path=^(%s/.*|.gbs.conf)" %
+                        packaging_dir,
+                    ])
+        if repo.has_branch("pristine-tar"):
+            argv.extend(["--git-pristine-tar"])
+
+    if 'source_rpm' in args and args.source_rpm:
+        argv.extend(['--git-builder=rpmbuild',
+                     '--git-rpmbuild-builddir=.',
+                     '--git-rpmbuild-builddir=.',
+                     '--git-rpmbuild-rpmdir=.',
+                     '--git-rpmbuild-sourcedir=.',
+                     '--git-rpmbuild-specdir=.',
+                     '--git-rpmbuild-srpmdir=.',
+                     '--git-rpmbuild-buildrootdir=.',
+                     '--short-circuit', '-bs',
+                     ])
+    else:
+        argv.extend(["--git-builder=osc", "--git-export-only"])
+
+    return argv
+
+def export_sources(repo, commit, export_dir, spec, args):
+    """
+    Export packaging files using git-buildpackage
+    """
+    tmp = utils.Temp(prefix='gbp_', dirn=configmgr.get('tmpdir', 'general'),
+                            directory=True)
+
+    gbp_args = create_gbp_export_args(repo, commit, export_dir, tmp.path,
+                                      spec, args)
+    try:
+        ret = gbp_build(gbp_args)
+        if ret == 2 and not is_native_pkg(repo, args):
+            # Try falling back to old logic of one monolithic tarball
+            msger.warning("Generating upstream tarball and/or generating "\
+                          "patches failed. GBS tried this as you have "\
+                          "upstream branch in you git tree. This is a new "\
+                          "mode introduced in GBS v0.10. "\
+                          "Consider fixing the problem by either:\n"\
+                          "  1. Update your upstream branch and/or fix the "\
+                          "spec file. Also, check the upstream tag format.\n"\
+                          "  2. Remove or rename the upstream branch")
+            msger.info("Falling back to the old method of generating one "\
+                       "monolithic source archive")
+            gbp_args = create_gbp_export_args(repo, commit, export_dir,
+                                              tmp.path, spec, args,
+                                              force_native=True)
+            ret = gbp_build(gbp_args)
+        if ret:
+            msger.error("Failed to export packaging files from git tree")
+    except GitRepositoryError, excobj:
+        msger.error("Repository error: %s" % excobj)
+
+
+def main(args):
+    """gbs export entry point."""
+
+    if args.commit and args.include_all:
+        raise errors.Usage('--commit can\'t be specified together with '\
+                           '--include-all')
+
+    workdir = args.gitdir
+    try:
+        repo = RpmGitRepository(workdir)
+    except GitRepositoryError, err:
+        msger.error(str(err))
+
+    utils.git_status_checker(repo, args)
+    workdir = repo.path
+
+    packaging_dir = get_packaging_dir(args)
+    if not os.path.exists(os.path.join(workdir, packaging_dir)):
+        msger.error("No packaging directory '%s/', so there is nothing to "
+                    "export." % packaging_dir)
+
+    # Only guess spec filename here, parse later when we have the correct
+    # spec file at hand
+    if args.commit:
+        commit = args.commit
+    elif args.include_all:
+        commit = 'WC.UNTRACKED'
+    else:
+        commit = 'HEAD'
+    relative_spec = utils.guess_spec(workdir, packaging_dir, args.spec, commit)
+
+    if args.outdir:
+        outdir = args.outdir
+    else:
+        outdir = os.path.join(workdir, packaging_dir)
+    outdir = os.path.abspath(outdir)
+    mkdir_p(outdir)
+    tmpdir     = configmgr.get('tmpdir', 'general')
+    tempd = utils.Temp(prefix=os.path.join(tmpdir, '.gbs_export_'), \
+                       directory=True)
+    export_dir = tempd.path
+
+    check_export_branches(repo, args)
+
+    with utils.Workdir(workdir):
+        export_sources(repo, commit, export_dir, relative_spec, args)
+
+    specfile = os.path.basename(relative_spec)
+    try:
+        spec = rpm.parse_spec(os.path.join(export_dir, specfile))
+    except GbpError, err:
+        msger.error('%s' % err)
+
+    if not spec.name or not spec.version:
+        msger.error('can\'t get correct name or version from spec file.')
+    else:
+        outdir = "%s/%s-%s-%s" % (outdir, spec.name, spec.upstreamversion,
+                                  spec.release)
+        shutil.rmtree(outdir, ignore_errors=True)
+        shutil.move(export_dir, outdir)
+        if args.source_rpm:
+            msger.info('source rpm generated to:\n     %s/%s.src.rpm' % \
+                       (outdir, os.path.basename(outdir)))
+
+    msger.info('package files have been exported to:\n     %s' % outdir)
diff --git a/gitbuildsys/cmd_import.py b/gitbuildsys/cmd_import.py
new file mode 100644 (file)
index 0000000..dffd136
--- /dev/null
@@ -0,0 +1,71 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2012 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""Implementation of subcmd: import
+"""
+import os
+
+from gitbuildsys import msger
+from gitbuildsys.cmd_export import get_packaging_dir
+from gitbuildsys.utils import Temp
+from gitbuildsys.conf import configmgr
+
+from gbp.scripts.import_srpm import main as gbp_import_srpm
+from gbp.scripts.import_orig_rpm import main as gbp_import_orig
+
+def main(args):
+    """gbs import entry point."""
+
+    if args.author_name:
+        os.environ["GIT_AUTHOR_NAME"] = args.author_name
+    if args.author_email:
+        os.environ["GIT_AUTHOR_EMAIL"] = args.author_email
+
+    path = args.path
+
+    tmp = Temp(prefix='gbp_',
+               dirn=configmgr.get('tmpdir', 'general'),
+               directory=True)
+
+    params = ["argv[0] placeholder",
+              "--color-scheme=magenta:green:yellow:red",
+              "--packaging-dir=%s" % get_packaging_dir(args),
+              "--upstream-branch=%s" % args.upstream_branch, path,
+              "--tmp-dir=%s" % tmp.path,
+              ]
+    if not args.no_pristine_tar and os.path.exists("/usr/bin/pristine-tar"):
+        params.append("--pristine-tar")
+
+    if path.endswith('.src.rpm') or path.endswith('.spec'):
+        ret = gbp_import_srpm(params)
+        if ret == 2:
+            msger.warning("Importing of patches into packaging branch failed! "
+                          "Please import manually (apply and commit to git, "
+                          "remove files from packaging dir and spec) in order "
+                          "to enable automatic patch generation.")
+        elif ret:
+            msger.error("Failed to import %s" % path)
+    else:
+        if args.merge:
+            params.append('--merge')
+        else:
+            params.append('--no-merge')
+        if gbp_import_orig(params):
+            msger.error('Failed to import %s' % path)
+
+    msger.info('done.')
diff --git a/gitbuildsys/cmd_remotebuild.py b/gitbuildsys/cmd_remotebuild.py
new file mode 100644 (file)
index 0000000..0a4f791
--- /dev/null
@@ -0,0 +1,248 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""Implementation of subcmd: build
+"""
+
+import os
+import glob
+
+from gitbuildsys import msger, errors, utils
+
+from gitbuildsys.conf import configmgr, encode_passwd
+from gitbuildsys.oscapi import OSC, OSCError
+from gitbuildsys.cmd_export import export_sources, get_packaging_dir
+from gitbuildsys.cmd_build import get_profile
+
+import gbp.rpm
+from gbp.rpm.git import GitRepositoryError, RpmGitRepository
+from gbp.errors import GbpError
+
+OSCRC_TEMPLATE = """[general]
+apiurl = %(apiurl)s
+plaintext_passwd=0
+use_keyring=0
+http_debug = %(http_debug)s
+debug = %(debug)s
+gnome_keyring=0
+[%(apiurl)s]
+user=%(user)s
+passx=%(passwdx)s
+"""
+
+
+def main(args):
+    """gbs remotebuild entry point."""
+
+    obsconf = get_profile(args).obs
+
+    if not obsconf or not obsconf.url:
+        msger.error('no obs api found, please add it to gbs conf and try again')
+
+    apiurl = obsconf.url
+
+    if not apiurl.user:
+        msger.error('empty user is not allowed for remotebuild, '
+                    'please add user/passwd to gbs conf, and try again')
+
+    if args.commit and args.include_all:
+        raise errors.Usage('--commit can\'t be specified together with '
+                           '--include-all')
+
+    obs_repo = args.repository
+    obs_arch = args.arch
+
+    if args.buildlog and None in (obs_repo, obs_arch):
+        msger.error('please specify arch(-A) and repository(-R)')
+
+    try:
+        repo = RpmGitRepository(args.gitdir)
+    except GitRepositoryError, err:
+        msger.error(str(err))
+
+    workdir = repo.path
+
+    if not (args.buildlog or args.status):
+        utils.git_status_checker(repo, args)
+
+    # TODO: check ./packaging dir at first
+    packaging_dir = get_packaging_dir(args)
+
+    if args.commit:
+        commit = args.commit
+    elif args.include_all:
+        commit = 'WC.UNTRACKED'
+    else:
+        commit = 'HEAD'
+
+    relative_spec = utils.guess_spec(workdir, packaging_dir, args.spec, commit)
+
+    if args.include_all:
+        # include_all means to use work copy,
+        # otherwise use the reversion in git history
+        spec_to_parse = os.path.join(workdir, relative_spec)
+    else:
+        content = utils.show_file_from_rev(workdir, relative_spec, commit)
+        if content is None:
+            msger.error('failed to checkout %s '
+                        'from commit: %s' % (relative_spec, commit))
+
+        tmp_spec = utils.Temp(content=content)
+        spec_to_parse = tmp_spec.path
+
+    # get 'name' and 'version' from spec file
+    try:
+        spec = gbp.rpm.parse_spec(spec_to_parse)
+    except GbpError, err:
+        msger.error('%s' % err)
+
+    if not spec.name:
+        msger.error('can\'t get correct name.')
+    package = spec.name
+
+    base_prj = None
+    if args.base_obsprj:
+        base_prj = args.base_obsprj
+    elif obsconf.base:
+        base_prj = obsconf.base
+
+    if args.target_obsprj is None:
+        if obsconf.target:
+            target_prj = obsconf.target
+        else:
+            target_prj = "home:%s:gbs" % apiurl.user
+            if base_prj:
+                target_prj += ":%s" % base_prj
+    else:
+        target_prj = args.target_obsprj
+
+    api_passwd = apiurl.passwd if apiurl.passwd else ''
+    # Create temporary oscrc
+    oscrc = OSCRC_TEMPLATE % {
+                "http_debug": 1 if msger.get_loglevel() == 'debug' else 0,
+                "debug": 1 if msger.get_loglevel() == 'verbose' else 0,
+                "apiurl": apiurl,
+                "user": apiurl.user,
+                "passwdx": encode_passwd(api_passwd),
+            }
+
+    tmpdir     = configmgr.get('tmpdir', 'general')
+    tmpd = utils.Temp(prefix=os.path.join(tmpdir, '.gbs_remotebuild_'),
+                      directory=True)
+    exportdir = tmpd.path
+    tmpf = utils.Temp(dirn=exportdir, prefix='.oscrc', content=oscrc)
+    oscrcpath = tmpf.path
+
+    api = OSC(apiurl, oscrc=oscrcpath)
+
+    try:
+        if args.buildlog:
+            archlist = []
+            status = api.get_results(target_prj, package)
+
+            for build_repo in status.keys():
+                for arch in status[build_repo]:
+                    archlist.append('%-15s%-15s' % (build_repo, arch))
+            if not obs_repo or not obs_arch or obs_repo not in status.keys() \
+                   or obs_arch not in status[obs_repo].keys():
+                msger.error('no valid repo / arch specified for buildlog, '\
+                            'valid arguments of repo and arch are:\n%s' % \
+                            '\n'.join(archlist))
+            if status[obs_repo][obs_arch] not in ['failed', 'succeeded',
+                                                  'building', 'finishing']:
+                msger.error('build status of %s for %s/%s is %s, no build log.'\
+                            % (package, obs_repo, obs_arch,
+                               status[obs_repo][obs_arch]))
+            msger.info('build log for %s/%s/%s/%s' % (target_prj, package,
+                                                      obs_repo, obs_arch))
+            print api.get_buildlog(target_prj, package, obs_repo, obs_arch)
+
+            return 0
+
+        if args.status:
+            results = []
+
+            status = api.get_results(target_prj, package)
+
+            for build_repo in status.keys():
+                for arch in status[build_repo]:
+                    stat = status[build_repo][arch]
+                    results.append('%-15s%-15s%-15s' % (build_repo, arch, stat))
+            msger.info('build results from build server:\n%s' \
+                       % '\n'.join(results))
+            return 0
+
+    except OSCError, err:
+        msger.error(str(err))
+
+    with utils.Workdir(workdir):
+        export_sources(repo, commit, exportdir, relative_spec, args)
+
+    try:
+        commit_msg = repo.get_commit_info(args.commit or 'HEAD')['subject']
+    except GitRepositoryError, exc:
+        msger.error('failed to get commit info: %s' % exc)
+
+    files = glob.glob("%s/*" % exportdir)
+    build_repos = None
+    try:
+        msger.info('checking status of obs project: %s ...' % target_prj)
+        if not api.exists(target_prj):
+            msger.info('creating new project %s' % (target_prj))
+            api.create_project(target_prj, base_prj)
+        else:
+            build_repos = api.get_repos_of_project(target_prj)
+            if not build_repos:
+                msger.warning("no available build repos for %s" % target_prj)
+        if api.exists(target_prj, package):
+            old, _not_changed, changed, new = api.diff_files(target_prj,
+                                                             package, files)
+            if old:
+                msger.info("removing old files from OBS project")
+                api.remove_files(target_prj, package, old)
+            commit_files = changed + new
+        else:
+            msger.info('creating new package %s/%s' % (target_prj, package))
+            api.create_package(target_prj, package)
+            # new project - submitting all local files
+            commit_files = files
+    except OSCError, err:
+        msger.error(str(err))
+
+    if not commit_files:
+        if build_repos:
+            msger.warning("no local changes found. Triggering rebuild")
+            api.rebuild(target_prj, package, obs_arch)
+        else:
+            msger.warning("no local changes found. can't trigger rebuild "
+                          "as no available build repos found")
+            return 0
+    else:
+        msger.info('commit packaging files to build server ...')
+        commit_files = [(fpath, fpath in commit_files) for fpath in files]
+        try:
+            api.commit_files(target_prj, package, commit_files, commit_msg)
+        except errors.ObsError, exc:
+            msger.error('commit packages fail: %s, please check the permission '
+                        'of target project:%s' % (exc, target_prj))
+
+        msger.info('local changes submitted to build server successfully')
+
+    msger.info('follow the link to monitor the build progress:\n'
+               '  %s/package/show?package=%s&project=%s' \
+               % (apiurl.replace('api', 'build'), package, target_prj))
diff --git a/gitbuildsys/cmd_submit.py b/gitbuildsys/cmd_submit.py
new file mode 100644 (file)
index 0000000..374eac0
--- /dev/null
@@ -0,0 +1,104 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2012 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""Implementation of subcmd: submit"""
+
+import os
+import time
+
+from gitbuildsys import msger
+from gitbuildsys.utils import edit
+
+from gbp.rpm.git import GitRepositoryError, RpmGitRepository
+
+
+
+def get_message():
+    '''
+    get message from editor
+    '''
+    prompt = '''
+# Please enter the message for your tag. Lines starting with '#'
+# will be ignored, and an empty message aborts the submission.
+#'''
+    raw = edit(prompt)
+    useful = [i for i in raw.splitlines() if not i.startswith('#') ]
+    return os.linesep.join(useful).strip()
+
+
+def main(args):
+    """gbs submit entry point."""
+
+    workdir = args.gitdir
+
+    if args.msg is None:
+        message = get_message()
+    else:
+        message = args.msg
+
+    if not message:
+        msger.error("tag message is required")
+
+    try:
+        repo = RpmGitRepository(workdir)
+        commit = repo.rev_parse(args.commit)
+        current_branch = repo.get_branch()
+    except GitRepositoryError, err:
+        msger.error(str(err))
+
+    try:
+        upstream = repo.get_upstream_branch(current_branch)
+    except GitRepositoryError:
+        upstream = None
+
+    if not args.remote:
+        if upstream:
+            args.remote = upstream.split('/')[0]
+        else:
+            msger.info("no upstream set for the current branch, using "
+                       "'origin' as the remote server")
+            args.remote = 'origin'
+    if not args.target:
+        if upstream and upstream.startswith(args.remote):
+            args.target = os.path.basename(upstream)
+        else:
+            msger.warning("Can't find upstream branch for current branch "
+                          "%s. Gbs uses the local branch name as the target. "
+                          "Please consider to use git-branch --set-upstream "
+                          "to set upstream remote branch." % current_branch)
+            args.target = current_branch
+
+    try:
+        if args.target == 'master':
+            args.target = 'trunk'
+        tagname = 'submit/%s/%s' % (args.target, time.strftime( \
+                                    '%Y%m%d.%H%M%S', time.gmtime()))
+        msger.info('creating tag: %s' % tagname)
+        repo.create_tag(tagname, msg=message, commit=commit, sign=args.sign,
+                        keyid=args.user_key)
+    except GitRepositoryError, err:
+        msger.error('failed to create tag %s: %s ' % (tagname, str(err)))
+
+    try:
+        msger.info("pushing tag to remote '%s'" % args.remote)
+        repo.push_tag(args.remote, tagname)
+    except GitRepositoryError, err:
+        repo.delete_tag(tagname)
+        msger.error('failed to push tag %s :%s' % (tagname, str(err)))
+
+    msger.info('done.')
diff --git a/gitbuildsys/conf.py b/gitbuildsys/conf.py
new file mode 100644 (file)
index 0000000..918fc87
--- /dev/null
@@ -0,0 +1,670 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+'''
+Provides classes and functions to read and write gbs.conf.
+'''
+
+from __future__ import with_statement
+import os
+import ast
+import base64
+import shutil
+from collections import namedtuple
+from ConfigParser import SafeConfigParser, NoSectionError, \
+                         MissingSectionHeaderError, Error
+
+from gitbuildsys import msger, errors
+from gitbuildsys.safe_url import SafeURL
+from gitbuildsys.utils import Temp
+
+
+def decode_passwdx(passwdx):
+    '''decode passwdx into plain format'''
+    return base64.b64decode(passwdx).decode('bz2')
+
+
+def encode_passwd(passwd):
+    '''encode passwd by bz2 and base64'''
+    return base64.b64encode(passwd.encode('bz2'))
+
+
+def evalute_string(string):
+    '''safely evaluate string'''
+    if string.startswith('"') or string.startswith("'"):
+        return ast.literal_eval(string)
+    return string
+
+
+def split_and_evaluate_string(string, sep=None, maxsplit=-1):
+    '''split a string and evaluate each of them'''
+    return [ evalute_string(i.strip()) for i in string.split(sep, maxsplit) ]
+
+
+class BrainConfigParser(SafeConfigParser):
+    """Standard ConfigParser derived class which can reserve most of the
+    comments, indents, and other user customized stuff inside the ini file.
+    """
+
+    def read_one(self, filename):
+        """only support one input file"""
+        return SafeConfigParser.read(self, filename)
+
+    def _read(self, fptr, fname):
+        """Parse a sectioned setup file.
+
+        Override the same method of parent class.
+
+        Customization: save filename and file contents
+        """
+
+        # save the original filepath and contents
+        self._fpname = fname
+        self._flines = fptr.readlines()
+        fptr.seek(0)
+
+        return SafeConfigParser._read(self, fptr, fname)
+
+    def _set_into_file(self, section, option, value, replace_opt=None):
+        """Set the value in the file contents
+
+        Parsing logic and lot of the code was copied directly from the
+        ConfigParser module of Python standard library.
+        """
+        cursect = None                        # None, or a str
+        optname = None
+        new_line = '%s = %s\n' % (option, value)
+        new_line_written = False
+        last_section_line = None
+
+        for lineno in range(len(self._flines)):
+            line = self._flines[lineno]
+            # We might have 'None' lines because of earlier updates
+            if line is None:
+                continue
+
+            # comment or blank line?
+            if line.strip() == '' or line[0] in '#;':
+                continue
+            if line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR":
+                # no leading whitespace
+                continue
+            # continuation line?
+            if line[0].isspace() and cursect == section and \
+                (optname == option or optname == replace_opt):
+                self._flines[lineno] = None
+            else:
+                # is it a section header?
+                match = self.SECTCRE.match(line)
+                if match:
+                    cursect = match.group('header')
+                    # So sections can't start with a continuation line
+                    optname = None
+                # no section header in the file?
+                elif cursect is None:
+                    raise MissingSectionHeaderError(self._fpname,
+                                                    lineno + 1, line)
+                # an option line?
+                else:
+                    match = self.OPTCRE.match(line)
+                    if match:
+                        optname = match.group('option')
+                        optname = self.optionxform(optname.rstrip())
+                        # Replace / remove options
+                        if cursect == section and \
+                           (optname == option or optname == replace_opt):
+                            if not new_line_written:
+                                self._flines[lineno] = new_line
+                                new_line_written = True
+                            else:
+                                # Just remove all matching lines, if we've
+                                # already written the new value
+                                self._flines[lineno] = None
+                    # Just ignore non-fatal parsing errors
+
+            # Save the last line of the matching section
+            if cursect == section:
+                last_section_line = lineno
+
+        # Insert new key
+        if not new_line_written:
+            if last_section_line is not None:
+                self._flines.insert(last_section_line + 1, new_line)
+            else:
+                raise NoSectionError(section)
+
+    def set_into_file(self, section, option, value, replace_opt=None):
+        """When set new value, need to update the readin file lines,
+        which can be saved back to file later.
+        """
+        try:
+            SafeConfigParser.set(self, section, option, value)
+            if replace_opt:
+                SafeConfigParser.remove_option(self, section, replace_opt)
+        except NoSectionError, err:
+            raise errors.ConfigError(str(err))
+
+        # If the code reach here, it means the section and key are ok
+        try:
+            self._set_into_file(section, option, value, replace_opt)
+        except Exception as err:
+            # This really shouldn't happen, we've already once parsed the file
+            # contents successfully.
+            raise errors.ConfigError('BUG: ' + str(err))
+
+    def update(self):
+        """Update the original config file using updated values"""
+
+        if self._fpname == '<???>':
+            return
+
+        with open(self._fpname, 'w') as fptr:
+            buf = ''.join([ line for line in self._flines if line is not None ])
+            fptr.write(buf)
+
+
+class ConfigMgr(object):
+    '''Support multi-levels of gbs.conf. Use this class to get and set
+    item value without caring about concrete ini format'''
+
+    DEFAULTS = {
+            'general': {
+                'tmpdir': '/var/tmp',
+                'editor': '',
+                'upstream_branch': 'upstream',
+                'upstream_tag': 'upstream/${upstreamversion}',
+                'squash_patches_until': '',
+                'buildroot':    '~/GBS-ROOT/',
+                'packaging_dir': 'packaging',
+            },
+    }
+
+    DEFAULT_CONF_TEMPLATE = '''[general]
+#Current profile name which should match a profile section name
+profile = profile.tizen
+
+[profile.tizen]
+#Common authentication info for whole profile
+#user =
+#CAUTION: please use the key name "passwd" to reset plaintext password
+#passwd =
+obs = obs.tizen
+#Comma separated list of repositories
+repos = repo.tizen_latest
+#repos = repo.tizen_main, repo.tizen_base
+
+[obs.tizen]
+#OBS API URL pointing to a remote OBS.
+url = https://api.tizen.org
+#Optional user and password, set if differ from profile's user and password
+#user =
+#passwd =
+
+#Repo section example
+[repo.tizen_latest]
+#Build against repo's URL
+url = http://download.tizen.org/releases/daily/trunk/ivi/latest/
+#Optional user and password, set if differ from profile's user and password
+#user =
+#passwd =
+
+#Individual repo is also supported
+#[repo.tizen_base]
+#url = http://download.tizen.org/releases/daily/trunk/ivi/latest/repos/base/ia32/packages/
+#[repo.tizen_main]
+#url = http://download.tizen.org/releases/daily/trunk/ivi/latest/repos/ivi/ia32/packages/
+'''
+
+    # make the manager class as singleton
+    _instance = None
+    def __new__(cls, *args, **kwargs):
+        if not cls._instance:
+            cls._instance = super(ConfigMgr, cls).__new__(cls, *args, **kwargs)
+
+        return cls._instance
+
+    def __init__(self, fpath=None):
+        self._cfgparsers = []
+        self.reset_from_conf(fpath)
+
+    def _create_default_parser(self):
+        'create a default parser that handle DEFAULTS values'
+        parser = BrainConfigParser()
+        for sec, options in self.DEFAULTS.iteritems():
+            parser.add_section(sec)
+            for key, val in options.iteritems():
+                parser.set(sec, key, val)
+        return parser
+
+    def reset_from_conf(self, fpath):
+        'reset all config values by files passed in'
+        if fpath:
+            if not os.path.exists(fpath):
+                raise errors.ConfigError('Configuration file %s does not '\
+                                         'exist' % fpath)
+            fpaths = [fpath]
+        else:
+            # use the default path
+            fpaths = self._lookfor_confs()
+            if not fpaths:
+                self._new_conf()
+                fpaths = self._lookfor_confs()
+
+        self._cfgparsers = []
+        for fpath in fpaths:
+            cfgparser = BrainConfigParser()
+            try:
+                cfgparser.read_one(fpath)
+            except Error, err:
+                raise errors.ConfigError('config file error:%s' % err)
+            self._cfgparsers.append(cfgparser)
+        self._cfgparsers.append(self._create_default_parser())
+
+        self._check_passwd()
+
+    @staticmethod
+    def _lookfor_confs():
+        """Look for available config files following the order:
+            > Current project
+            > User
+            > System
+        """
+
+        paths = []
+        for path in (os.path.abspath('.gbs.conf'),
+                     os.path.expanduser('~/.gbs.conf'),
+                     '/etc/gbs.conf'):
+            if os.path.exists(path) and path not in paths:
+                paths.append(path)
+
+        return paths
+
+    def _new_conf(self):
+        'generate a default conf file in home dir'
+        fpath = os.path.expanduser('~/.gbs.conf')
+
+        with open(fpath, 'w') as wfile:
+            wfile.write(self.DEFAULT_CONF_TEMPLATE)
+        os.chmod(fpath, 0600)
+
+        msger.warning('Created a new config file %s. Please check and edit '
+            'your authentication information.' % fpath)
+
+    def _check_passwd(self):
+        'convert passwd item to passwdx and then update origin conf files'
+        dirty = set()
+
+        all_sections = set()
+        for layer in self._cfgparsers:
+            for sec in layer.sections():
+                all_sections.add(sec)
+
+        for sec in all_sections:
+            for key in self.options(sec):
+                if key.endswith('passwd'):
+                    for cfgparser in self._cfgparsers:
+                        if cfgparser.has_option(sec, key):
+                            plainpass = cfgparser.get(sec, key)
+                            if plainpass is None:
+                                # empty string password is acceptable here
+                                continue
+                            cfgparser.set_into_file(sec,
+                                     key + 'x',
+                                     encode_passwd(plainpass),
+                                     key)
+                            dirty.add(cfgparser)
+
+        if dirty:
+            msger.warning('plaintext password in config files will '
+                          'be replaced by encoded ones')
+            self.update(dirty)
+
+    def _get(self, opt, section='general'):
+        'get value from multi-levels of config file'
+        for cfgparser in self._cfgparsers:
+            try:
+                return cfgparser.get(section, opt)
+            except Error, err:
+                pass
+        raise errors.ConfigError(err)
+
+    def options(self, section='general'):
+        'merge and return options of certain section from multi-levels'
+        sect_found = False
+        options = set()
+        for cfgparser in self._cfgparsers:
+            try:
+                options.update(cfgparser.options(section))
+                sect_found = True
+            except Error, err:
+                pass
+
+        if not sect_found:
+            raise errors.ConfigError(err)
+
+        return options
+
+    def has_section(self, section):
+        'indicate whether a section exists'
+        for parser in self._cfgparsers:
+            if parser.has_section(section):
+                return True
+        return False
+
+    def get(self, opt, section='general'):
+        'get item value. return plain text of password if item is passwd'
+        if opt == 'passwd':
+            val = self._get('passwdx', section)
+            try:
+                return decode_passwdx(val)
+            except (TypeError, IOError), err:
+                raise errors.ConfigError('passwdx:%s' % err)
+        else:
+            return self._get(opt, section)
+
+    @staticmethod
+    def update(cfgparsers):
+        'update changed values into files on disk'
+        for cfgparser in cfgparsers:
+            try:
+                cfgparser.update()
+            except IOError, err:
+                msger.warning('update config file error: %s' % err)
+
+
+URL = namedtuple('URL', 'url user password')
+
+
+class OBSConf(object):
+    'Config items related to obs section'
+
+    def __init__(self, parent, name, url, base, target):
+        self.parent = parent
+        self.name = name
+        self.base = base
+        self.target = target
+
+        user = url.user or parent.common_user
+        password = url.password or parent.common_password
+        try:
+            self.url = SafeURL(url.url, user, password)
+        except ValueError, err:
+            raise errors.ConfigError('%s for %s' % (str(err), url.url))
+
+    def dump(self, fhandler):
+        'dump ini to file object'
+        parser = BrainConfigParser()
+        parser.add_section(self.name)
+
+        parser.set(self.name, 'url', self.url)
+
+        if self.url.user and self.url.user != self.parent.common_user:
+            parser.set(self.name, 'user', self.url.user)
+
+        if self.url.passwd and self.url.passwd != self.parent.common_password:
+            parser.set(self.name, 'passwdx',
+                       encode_passwd(self.url.passwd))
+
+        if self.base:
+            parser.set(self.name, 'base_prj', self.base)
+
+        if self.target:
+            parser.set(self.name, 'target_prj', self.target)
+        parser.write(fhandler)
+
+
+class RepoConf(object):
+    'Config items related to repo section'
+
+    def __init__(self, parent, name, url):
+        self.parent = parent
+        self.name = name
+
+        user = url.user or parent.common_user
+        password = url.password or parent.common_password
+        try:
+            self.url = SafeURL(url.url, user, password)
+        except ValueError, err:
+            raise errors.ConfigError('%s for %s' % (str(err), url.url))
+
+    def dump(self, fhandler):
+        'dump ini to file object'
+        parser = BrainConfigParser()
+        parser.add_section(self.name)
+
+        parser.set(self.name, 'url', self.url)
+
+        if self.url.user and self.url.user != self.parent.common_user:
+            parser.set(self.name, 'user', self.url.user)
+
+        if self.url.passwd and self.url.passwd != self.parent.common_password:
+            parser.set(self.name, 'passwdx',
+                       encode_passwd(self.url.passwd))
+        parser.write(fhandler)
+
+
+class Profile(object):
+    '''Profile which contains all config values related to same domain'''
+
+    def __init__(self, name, user, password):
+        self.name = name
+        self.common_user = user
+        self.common_password = password
+        self.repos = []
+        self.obs = None
+        self.buildroot = None
+
+    def add_repo(self, repoconf):
+        '''add a repo to repo list of the profile'''
+        self.repos.append(repoconf)
+
+    def set_obs(self, obsconf):
+        '''set OBS api of the profile'''
+        self.obs = obsconf
+
+    def dump(self, fhandler):
+        'dump ini to file object'
+        parser = BrainConfigParser()
+        parser.add_section(self.name)
+
+        if self.common_user:
+            parser.set(self.name, 'user', self.common_user)
+        if self.common_password:
+            parser.set(self.name, 'passwdx',
+                       encode_passwd(self.common_password))
+        if self.buildroot:
+            parser.set(self.name, 'buildroot', self.buildroot)
+
+        if self.obs:
+            parser.set(self.name, 'obs', self.obs.name)
+            self.obs.dump(fhandler)
+
+        if self.repos:
+            names = []
+            for repo in self.repos:
+                names.append(repo.name)
+                repo.dump(fhandler)
+            parser.set(self.name, 'repos', ', '.join(names))
+        parser.write(fhandler)
+
+
+class BizConfigManager(ConfigMgr):
+    '''config manager which handles high level conception, such as profile info
+    '''
+
+    def is_profile_oriented(self):
+        '''return True if config file is profile oriented'''
+        return self.get_optional_item('general', 'profile') is not None
+
+    def get_current_profile(self):
+        '''get profile current used'''
+        if self.is_profile_oriented():
+            return self.build_profile_by_name(self.get('profile'))
+
+        profile = self._build_profile_by_subcommand()
+        self.convert_to_new_style(profile)
+        return profile
+
+    def convert_to_new_style(self, profile):
+        'convert ~/.gbs.conf to new style'
+        def dump_general(fhandler):
+            'dump options in general section'
+            parser = BrainConfigParser()
+            parser.add_section('general')
+            parser.set('general', 'profile', profile.name)
+
+            for opt in self.options('general'):
+                val = self.get(opt)
+                if val != self.DEFAULTS['general'].get(opt):
+                    parser.set('general', opt, val)
+            parser.write(fhandler)
+
+        fname = '~/.gbs.conf.template'
+        try:
+            tmp = Temp()
+            with open(tmp.path, 'w') as fhandler:
+                dump_general(fhandler)
+                profile.dump(fhandler)
+            shutil.move(tmp.path, os.path.expanduser(fname))
+        except IOError, err:
+            raise errors.ConfigError(err)
+
+        msger.warning('subcommand oriented style of config is deprecated. '
+            'Please check %s, a new profile oriented style of config which'
+            ' was converted from your current settings.' % fname)
+
+    def get_optional_item(self, section, option, default=None):
+        '''return default if section.option does not exist'''
+        try:
+            return self.get(option, section)
+        except errors.ConfigError:
+            return default
+
+    def _get_url_options(self, section_id):
+        '''get url/user/passwd from a section'''
+        url = self.get('url', section_id)
+        user = self.get_optional_item(section_id, 'user')
+        password = self.get_optional_item(section_id, 'passwd')
+        return URL(url, user, password)
+
+    def build_profile_by_name(self, name):
+        '''return profile object by a given section'''
+        if not name.startswith('profile.'):
+            raise errors.ConfigError('section name specified by general.profile'
+                ' must start with string "profile.": %s' % name)
+        if not self.has_section(name):
+            raise errors.ConfigError('no such section: %s' % name)
+
+        user = self.get_optional_item(name, 'user')
+        password = self.get_optional_item(name, 'passwd')
+
+        profile = Profile(name, user, password)
+
+        obs = self.get_optional_item(name, 'obs')
+        if obs:
+            if not obs.startswith('obs.'):
+                raise errors.ConfigError('obs section name should start '
+                                         'with string "obs.": %s' % obs)
+
+            obsconf = OBSConf(profile, obs,
+                              self._get_url_options(obs),
+                              self.get_optional_item(obs, 'base_prj'),
+                              self.get_optional_item(obs, 'target_prj'))
+            profile.set_obs(obsconf)
+
+        repos = self.get_optional_item(name, 'repos')
+        if repos:
+            for repo in repos.split(','):
+                repo = repo.strip()
+                if not repo.startswith('repo.'):
+                    msger.warning('ignore %s, repo section name should start '
+                                  'with string "repo."' % repo)
+                    continue
+
+                repoconf = RepoConf(profile, repo,
+                                    self._get_url_options(repo))
+                profile.add_repo(repoconf)
+
+        profile.buildroot = self.get_optional_item(name, 'buildroot')
+
+        return profile
+
+    def _parse_build_repos(self):
+        """
+        Make list of urls using repox.url, repox.user and repox.passwd
+        configuration file parameters from 'build' section.
+        Validate configuration parameters.
+        """
+        repos = {}
+        # get repo settings form build section
+        for opt in self.options('build'):
+            if opt.startswith('repo'):
+                try:
+                    key, name = opt.split('.')
+                except ValueError:
+                    raise errors.ConfigError("invalid repo option: %s" % opt)
+
+                if name not in ('url', 'user', 'passwdx'):
+                    raise errors.ConfigError("invalid repo option: %s" % opt)
+
+                if key not in repos:
+                    repos[key] = {}
+
+                if name in repos[key]:
+                    raise errors.ConfigError('Duplicate entry %s' % opt)
+
+                value = self.get(opt, 'build')
+                if name == 'passwdx':
+                    try:
+                        value = decode_passwdx(value)
+                    except (TypeError, IOError), err:
+                        raise errors.ConfigError('Error decoding %s: %s' % \
+                                                 (opt, err))
+                    repos[key]['passwd'] = value
+                else:
+                    repos[key][name] = value
+        return sorted(repos.items(), key=lambda i: i[0])
+
+    def _build_profile_by_subcommand(self):
+        '''return profile object from subcommand oriented style of config'''
+        profile = Profile('profile.current', None, None)
+
+        sec = 'remotebuild'
+        addr = self.get_optional_item(sec, 'build_server')
+        if addr:
+            user = self.get_optional_item(sec, 'user')
+            password = self.get_optional_item(sec, 'passwd')
+            url = URL(addr, user, password)
+
+            obsconf = OBSConf(profile, 'obs.%s' % sec, url,
+                self.get_optional_item('remotebuild', 'base_prj'),
+                self.get_optional_item('remotebuild', 'target_prj'))
+            profile.set_obs(obsconf)
+
+        repos = self._parse_build_repos()
+        for key, item in repos:
+            if 'url' not in item:
+                raise errors.ConfigError("URL is not specified for %s" % key)
+            url = URL(item['url'], item.get('user'), item.get('passwd'))
+
+            repoconf = RepoConf(profile, 'repo.%s' % key, url)
+            profile.add_repo(repoconf)
+
+        return profile
+
+
+configmgr = BizConfigManager()
diff --git a/gitbuildsys/errors.py b/gitbuildsys/errors.py
new file mode 100644 (file)
index 0000000..657001d
--- /dev/null
@@ -0,0 +1,55 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+class CmdError(Exception):
+    """An exception base class for all command calling errors."""
+    keyword = ''
+
+    def __str__(self):
+        return self.keyword + str(self.args[0])
+
+class Usage(CmdError):
+    keyword = '<usage>'
+
+    def __str__(self):
+        return self.keyword + str(self.args[0]) + \
+                ', please use "--help" for more info'
+
+class ConfigError(CmdError):
+    keyword = '<config>'
+
+class ObsError(CmdError):
+    keyword = '<obs>'
+
+class UnpackError(CmdError):
+    keyword = '<unpack>'
+
+class FormatError(CmdError):
+    keyword = '<format>'
+
+class QemuError(CmdError):
+    keyword = '<qemu>'
+
+class Abort(CmdError):
+    keyword = ''
+
+class UrlError(CmdError):
+    keyword = '<url>'
+
+class GbsError(CmdError):
+    keyword = '<gbs>'
diff --git a/gitbuildsys/msger.py b/gitbuildsys/msger.py
new file mode 100644 (file)
index 0000000..1011863
--- /dev/null
@@ -0,0 +1,454 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2009, 2010, 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os, sys
+import re
+import time
+
+__ALL__ = ['set_mode',
+           'get_loglevel',
+           'set_loglevel',
+           'set_logfile',
+           'enable_logstderr',
+           'disable_logstderr',
+           'raw',
+           'debug',
+           'verbose',
+           'info',
+           'warning',
+           'error',
+           'ask',
+           'pause',
+           'waiting',
+           'PrintBuf',
+           'PrintBufWrapper',
+          ]
+
+# COLORs in ANSI
+INFO_COLOR = 32 # green
+WARN_COLOR = 33 # yellow
+ERR_COLOR  = 31 # red
+ASK_COLOR  = 34 # blue
+DEBUG_COLOR = 35 # Magenta
+NO_COLOR = 0
+
+# save the timezone info at import time
+HOST_TIMEZONE = time.timezone
+
+PREFIX_RE = re.compile('^<(.*?)>\s*(.*)', re.S)
+
+INTERACTIVE = True
+
+LOG_LEVEL = 1
+LOG_LEVELS = {
+                'quiet': 0,
+                'normal': 1,
+                'verbose': 2,
+                'debug': 3,
+                'never': 4,
+             }
+
+LOG_FILE_FP = None
+LOG_CONTENT = ''
+CATCHERR_BUFFILE_FD = -1
+CATCHERR_BUFFILE_PATH = None
+CATCHERR_SAVED_2 = -1
+
+# save the original stdout/stderr at the very start
+STDOUT = sys.stdout
+STDERR = sys.stderr
+
+# Configure gbp logging
+import gbp.log
+for level in (gbp.log.DEBUG, gbp.log.INFO, gbp.log.WARNING, gbp.log.ERROR):
+    gbp.log.logging.addLevelName(level,
+                                 gbp.log.logging.getLevelName(level).lower())
+gbp.log.LOGGER.set_format('%(color)s%(levelname)s: '
+                          '%(coloroff)s%(message)s')
+
+# Mapping for gbs->gbp log levels
+GBP_LOG_LEVELS = {
+                    'quiet': gbp.log.ERROR,
+                    'normal': gbp.log.INFO,
+                    'verbose': gbp.log.DEBUG,
+                    'debug': gbp.log.DEBUG,
+                    'never': gbp.log.ERROR
+                 }
+
+class PrintBuf(object):
+    """Object to buffer the output of 'print' statement string
+    """
+
+    def __init__(self):
+        self.buf1 = \
+        self.buf2 = \
+        self.old1 = \
+        self.old2 = None
+
+    def start(self):
+        """Start to buffer, redirect stdout to string
+        """
+
+        if get_loglevel() != 'debug':
+            import StringIO
+            self.buf1 = StringIO.StringIO()
+            self.buf2 = StringIO.StringIO()
+
+            self.old1 = sys.stdout
+            self.old2 = sys.stderr
+            sys.stdout = self.buf1
+            sys.stderr = self.buf2
+
+    def stop(self):
+        """Stop buffer, restore the original stdout, and flush the
+        buffer string, return the content
+        """
+
+        if self.buf1:
+            msg1 = self.buf1.getvalue().strip()
+            msg2 = self.buf2.getvalue().strip()
+            self.buf1.close()
+            self.buf2.close()
+
+            sys.stdout = self.old1
+            sys.stderr = self.old2
+
+            self.buf1 = \
+            self.buf2 = \
+            self.old1 = \
+            self.old2 = None
+
+            return (msg1, msg2)
+
+        return ('', '')
+
+class PrintBufWrapper(object):
+    """Wrapper class for another class, to catch the print output and
+    handlings.
+    """
+
+    def __init__(self, wrapped_class, msgfunc_1, msgfunc_2, *args, **kwargs):
+        """Arguments:
+          wrapped_class: the class to be wrapped
+          msgfunc_1: function to deal with msg from stdout(1)
+          msgfunc_2: function to deal with msg from stderr(2)
+          *args, **kwargs: the original args of wrapped_class
+        """
+
+        self.pbuf = PrintBuf()
+        self.func1 = msgfunc_1
+        self.func2 = msgfunc_2
+
+        self.pbuf.start()
+        self.wrapped_inst = wrapped_class(*args, **kwargs)
+        stdout_msg, stderr_msg = self.pbuf.stop()
+        if stdout_msg:
+            self.func1(stdout_msg)
+        if stderr_msg:
+            self.func2(stderr_msg)
+
+    def __getattr__(self, attr):
+        orig_attr = getattr(self.wrapped_inst, attr)
+        if callable(orig_attr):
+            def hooked(*args, **kwargs):
+                self.pbuf.start()
+                try:
+                    result = orig_attr(*args, **kwargs)
+                except:
+                    raise
+                finally:
+                    stdout_msg, stderr_msg = self.pbuf.stop()
+                    if stdout_msg:
+                        self.func1(stdout_msg)
+                    if stderr_msg:
+                        self.func2(stderr_msg)
+
+                return result
+
+            return hooked
+        else:
+            return orig_attr
+
+def _general_print(head, color, msg = None, stream = None, level = 'normal'):
+    global LOG_CONTENT
+
+    if LOG_LEVELS[level] > LOG_LEVEL:
+        # skip
+        return
+
+    if stream is None:
+        stream = STDOUT
+
+    errormsg = ''
+    if CATCHERR_BUFFILE_FD > 0:
+        size = os.lseek(CATCHERR_BUFFILE_FD , 0, os.SEEK_END)
+        os.lseek(CATCHERR_BUFFILE_FD, 0, os.SEEK_SET)
+        errormsg = os.read(CATCHERR_BUFFILE_FD, size)
+        os.ftruncate(CATCHERR_BUFFILE_FD, 0)
+
+    if LOG_FILE_FP:
+        if errormsg:
+            LOG_CONTENT += errormsg
+
+        if msg and msg.strip():
+            timestr = time.strftime("[%m/%d %H:%M:%S] ",
+                                    time.gmtime(time.time() - HOST_TIMEZONE))
+            LOG_CONTENT += timestr + msg.strip() + '\n'
+
+    if errormsg:
+        _color_print('', NO_COLOR, errormsg, stream, level)
+
+    _color_print(head, color, msg, stream, level)
+
+def _color_print(head, color, msg, stream, _level):
+    colored = True
+    if color == NO_COLOR or \
+       not stream.isatty() or \
+       os.getenv('ANSI_COLORS_DISABLED') is not None:
+        colored = False
+
+    if head.startswith('\r'):
+        # need not \n at last
+        newline = False
+    else:
+        newline = True
+
+    if colored:
+        head = '\033[%dm%s:\033[0m ' % (color, head)
+        if not newline:
+            # ESC cmd to clear line
+            head = '\033[2K' + head
+    else:
+        if head:
+            head += ': '
+            if head.startswith('\r'):
+                head = head.lstrip()
+                newline = True
+
+    if msg is not None:
+        stream.write('%s%s' % (head, msg))
+        if newline:
+            stream.write('\n')
+
+    stream.flush()
+
+def _color_perror(head, color, msg, level = 'normal'):
+    if CATCHERR_BUFFILE_FD > 0:
+        _general_print(head, color, msg, STDOUT, level)
+    else:
+        _general_print(head, color, msg, STDERR, level)
+
+def _split_msg(head, msg):
+    if isinstance(msg, list):
+        msg = '\n'.join(map(str, msg))
+
+    if msg.startswith('\n'):
+        # means print \n at first
+        msg = msg.lstrip()
+        head = '\n' + head
+
+    elif msg.startswith('\r'):
+        # means print \r at first
+        msg = msg.lstrip()
+        head = '\r' + head
+
+    match = PREFIX_RE.match(msg)
+    if match:
+        head += ' <%s>' % match.group(1)
+        msg = match.group(2)
+
+    return head, msg
+
+def get_loglevel():
+    return (k for k, v in LOG_LEVELS.items() if v==LOG_LEVEL).next()
+
+def set_loglevel(level):
+    global LOG_LEVEL
+    if level not in LOG_LEVELS:
+        # no effect
+        return
+
+    LOG_LEVEL = LOG_LEVELS[level]
+
+    # set git-buildpackage log level
+    gbp.log.LOGGER.setLevel(GBP_LOG_LEVELS[level])
+
+def set_interactive(mode=True):
+    global INTERACTIVE
+    if mode:
+        INTERACTIVE = True
+    else:
+        INTERACTIVE = False
+
+def raw(msg=''):
+    _general_print('', NO_COLOR, msg)
+
+def info(msg):
+    head, msg = _split_msg('info', msg)
+    _general_print(head, INFO_COLOR, msg)
+
+def verbose(msg):
+    head, msg = _split_msg('verbose', msg)
+    _general_print(head, INFO_COLOR, msg, level = 'verbose')
+
+def warning(msg):
+    head, msg = _split_msg('warning', msg)
+    _color_perror(head, WARN_COLOR, msg)
+
+def debug(msg):
+    head, msg = _split_msg('debug', msg)
+    _color_perror(head, DEBUG_COLOR, msg, level = 'debug')
+
+def error(msg):
+    head, msg = _split_msg('error', msg)
+    _color_perror(head, ERR_COLOR, msg)
+    sys.exit(1)
+
+def waiting(func):
+    """
+    Function decorator to show simple waiting message for
+    long time operations.
+    """
+
+    import functools
+
+    @functools.wraps(func)
+    def _wait_with_print(*args, **kwargs):
+        import threading
+
+        class _WaitingTimer(threading.Thread):
+            def __init__(self):
+                threading.Thread.__init__(self)
+                self.event = threading.Event()
+                self.waited = False
+
+            def run(self):
+                while not self.event.is_set():
+                    # put the waiting above the actual
+                    # printing to avoid unnecessary msg
+                    self.event.wait(1)
+                    if self.event.is_set():
+                        break
+
+                    self.waited = True
+                    STDERR.write('.')
+                    STDERR.flush()
+
+            def stop(self):
+                self.event.set()
+
+                if self.waited:
+                    STDERR.write('\n')
+                    STDERR.flush()
+
+        timer = _WaitingTimer()
+        timer.start()
+
+        try:
+            out = func(*args, **kwargs)
+        except:
+            raise
+        finally:
+            timer.stop()
+
+        return out
+
+    return _wait_with_print
+
+def ask(msg, default=True):
+    _general_print('\rQ', ASK_COLOR, '')
+    try:
+        if default:
+            msg += '(Y/n) '
+        else:
+            msg += '(y/N) '
+        if INTERACTIVE:
+            while True:
+                repl = raw_input(msg)
+                if repl.lower() == 'y':
+                    return True
+                elif repl.lower() == 'n':
+                    return False
+                elif not repl.strip():
+                    # <Enter>
+                    return default
+
+                # else loop
+        else:
+            if default:
+                msg += ' Y'
+            else:
+                msg += ' N'
+            _general_print('', NO_COLOR, msg)
+
+            return default
+    except KeyboardInterrupt:
+        sys.stdout.write('\n')
+        sys.exit(2)
+
+def pause(msg=None):
+    if INTERACTIVE:
+        _general_print('\rQ', ASK_COLOR, '')
+        if msg is None:
+            msg = 'press <ENTER> to continue ...'
+        raw_input(msg)
+
+def set_logfile(fpath):
+    global LOG_FILE_FP
+
+    def _savelogf():
+        if LOG_FILE_FP:
+            if not os.path.exists(os.path.dirname(LOG_FILE_FP)):
+                os.makedirs(os.path.dirname(LOG_FILE_FP))
+            fhandle = open(LOG_FILE_FP, 'w')
+            fhandle.write(LOG_CONTENT)
+            fhandle.close()
+
+    if LOG_FILE_FP is not None:
+        warning('duplicate log file configuration')
+
+    LOG_FILE_FP = os.path.abspath(os.path.expanduser(fpath))
+
+    import atexit
+    atexit.register(_savelogf)
+
+def enable_logstderr(fpath):
+    global CATCHERR_BUFFILE_FD
+    global CATCHERR_BUFFILE_PATH
+    global CATCHERR_SAVED_2
+
+    if os.path.exists(fpath):
+        os.remove(fpath)
+    CATCHERR_BUFFILE_PATH = fpath
+    CATCHERR_BUFFILE_FD = os.open(CATCHERR_BUFFILE_PATH, os.O_RDWR|os.O_CREAT)
+    CATCHERR_SAVED_2 = os.dup(2)
+    os.dup2(CATCHERR_BUFFILE_FD, 2)
+
+def disable_logstderr():
+    global CATCHERR_BUFFILE_FD
+    global CATCHERR_BUFFILE_PATH
+    global CATCHERR_SAVED_2
+
+    raw(msg=None) # flush message buffer and print it
+    os.dup2(CATCHERR_SAVED_2, 2)
+    os.close(CATCHERR_SAVED_2)
+    os.close(CATCHERR_BUFFILE_FD)
+    os.unlink(CATCHERR_BUFFILE_PATH)
+    CATCHERR_BUFFILE_FD = -1
+    CATCHERR_BUFFILE_PATH = None
+    CATCHERR_SAVED_2 = -1
diff --git a/gitbuildsys/oscapi.py b/gitbuildsys/oscapi.py
new file mode 100644 (file)
index 0000000..107914e
--- /dev/null
@@ -0,0 +1,342 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2012 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""
+This module provides wrapper class around OSC API.
+Only APIs which are required by cmd_remotebuild present here.
+
+"""
+
+import os
+import urllib2
+import M2Crypto
+from M2Crypto.SSL.Checker import SSLVerificationError
+import ssl
+
+from collections import defaultdict
+from urllib import quote_plus, pathname2url
+
+from gitbuildsys import msger
+from gitbuildsys.utils import hexdigest
+from gitbuildsys.errors import ObsError
+
+from osc import conf, core
+
+
+class OSCError(Exception):
+    """Local exception class."""
+    pass
+
+
+class OSC(object):
+    """Interface to OSC API"""
+
+    def __init__(self, apiurl=None, oscrc=None):
+        if oscrc:
+            try:
+                conf.get_config(override_conffile = oscrc)
+            except OSError, err:
+                if err.errno == 1:
+                    # permission problem, should be the chmod(0600) issue
+                    raise ObsError('Current user has no write permission '\
+                                   'for specified oscrc: %s' % oscrc)
+
+                raise # else
+            except urllib2.URLError:
+                raise ObsError("invalid service apiurl: %s" % apiurl)
+        else:
+            conf.get_config()
+
+        if apiurl:
+            self.apiurl = apiurl
+        else:
+            self.apiurl = conf.config['apiurl']
+
+    @staticmethod
+    def core_http(method, url, data=None, filep=None):
+        """Wrapper above core.<http_METHOD> to catch exceptions."""
+
+        # Workarounded osc bug. http_GET sometimes returns empty response
+        # Usually next try succeeds, so let's try 3 times
+        for count in (1, 2, 3):
+            try:
+                return method(url, data=data, file=filep)
+            except (urllib2.URLError, M2Crypto.m2urllib2.URLError,
+                    M2Crypto.SSL.SSLError, ssl.SSLError), err:
+                if count == 3:
+                    raise OSCError(str(err))
+
+        raise OSCError('Got empty response from %s %s' % \
+                       (method.func_name.split('_')[-1], url))
+
+    def get_repos_of_project(self, project):
+        repos = defaultdict(list)
+        for repo in core.get_repos_of_project(self.apiurl, project):
+            repos[repo.name].append(repo.arch)
+        return repos
+
+    def create_project(self, target, src=None, rewrite=False):
+        """
+        Create new OBS project based on existing project.
+        Copy config and repositories from src project to target
+        if src exists.
+        """
+
+        if src and not self.exists(src):
+            raise ObsError('base project: %s not exists' % src)
+
+        if self.exists(target):
+            msger.warning('target project: %s exists' % target)
+            if rewrite:
+                msger.warning('rewriting target project %s' % target)
+            else:
+                return
+
+        # Create target meta
+        meta = '<project name="%s"><title></title><description></description>'\
+               '<person role="maintainer" userid="%s"/>' % \
+               (target, conf.get_apiurl_usr(self.apiurl))
+
+        # Collect source repos if src project exist
+        if src:
+            # Copy repos to target
+            repos = self.get_repos_of_project(src)
+            for name in repos:
+                meta += '<repository name="%s">' % name
+                meta += '<path project="%s" repository="%s" />' % (src, name)
+                for arch in repos[name]:
+                    meta += "<arch>%s</arch>\n" % arch
+                meta += "</repository>\n"
+        else:
+            msger.warning('no project repos in target project, please add '
+                'repos from OBS webUI manually, or specify base project '
+                'with -B <base_prj>, then gbs can help to set repos '
+                'using the settings of the specified base project.')
+        meta += "</project>\n"
+
+        try:
+            # Create project and set its meta
+            core.edit_meta('prj', path_args=quote_plus(target), data=meta)
+        except (urllib2.URLError, M2Crypto.m2urllib2.URLError,
+                M2Crypto.SSL.SSLError), err:
+            raise ObsError("Can't set meta for %s: %s" % (target, str(err)))
+
+        # don't need set project config if no src project
+        if not src:
+            return
+
+        # copy project config
+        try:
+            config = core.show_project_conf(self.apiurl, src)
+        except (urllib2.URLError, M2Crypto.m2urllib2.URLError,
+                M2Crypto.SSL.SSLError), err:
+            raise ObsError("Can't get config from project %s: %s" \
+                           % (src, str(err)))
+
+        url = core.make_meta_url("prjconf", quote_plus(target),
+                                 self.apiurl, False)
+        try:
+            self.core_http(core.http_PUT, url, data=''.join(config))
+        except OSCError, err:
+            raise ObsError("can't copy config from %s to %s: %s" \
+                           % (src, target, err))
+
+    def exists(self, prj, pkg=''):
+        """Check if project or package exists."""
+
+        metatype = 'prj'
+        path_args = [core.quote_plus(prj)]
+        err = None
+        try:
+            core.meta_exists(metatype = metatype, path_args = tuple(path_args),
+                             create_new = False, apiurl = self.apiurl)
+            if not pkg:
+                return True
+
+            return pkg in core.meta_get_packagelist(self.apiurl, prj)
+        except urllib2.HTTPError, err:
+            if err.code == 404:
+                return False
+        except (urllib2.URLError, M2Crypto.m2urllib2.URLError, \
+                                  M2Crypto.SSL.SSLError), err:
+            pass
+        except SSLVerificationError:
+            raise ObsError("SSL verification error.")
+        if err:
+            raise ObsError("can't check if %s/%s exists: %s" % (prj, pkg, err))
+
+        return False
+
+    def rebuild(self, prj, pkg, arch):
+        """Rebuild package."""
+        try:
+            return core.rebuild(self.apiurl, prj, pkg, repo=None, arch=arch)
+        except (urllib2.URLError, M2Crypto.m2urllib2.URLError, \
+                M2Crypto.SSL.SSLError), err:
+            raise ObsError("Can't trigger rebuild for %s/%s: %s" % \
+                           (prj, pkg, str(err)))
+        except SSLVerificationError:
+            raise ObsError("SSL verification error.")
+
+    def diff_files(self, prj, pkg, paths):
+        """
+        Find difference between local and remote filelists
+        Return 4 lists: (old, not changed, changed, new)
+        where:
+           old - present only remotely
+           changed - present remotely and locally and differ
+           not changed - present remotely and locally and does not not differ
+           new - present only locally
+        old is a list of remote filenames
+        changed, not changed and new are lists of local filepaths
+        """
+
+        # Get list of files from the OBS
+        rfiles = core.meta_get_filelist(self.apiurl, prj, pkg, verbose=True)
+
+        old, not_changed, changed, new = [], [], [], []
+
+        if not rfiles:
+            # no remote files - all local files are new
+            return old, not_changed, changed, paths[:]
+
+        # Helper dictionary helps to avoid looping over remote files
+        rdict = dict((fobj.name, (fobj.size, fobj.md5)) for fobj in rfiles)
+
+        for lpath in paths:
+            lname = os.path.basename(lpath)
+            if lname in rdict:
+                lsize = os.path.getsize(lpath)
+                rsize, rmd5 = rdict[lname]
+                if rsize == lsize and rmd5 == core.dgst(lpath):
+                    not_changed.append(lpath)
+                else:
+                    changed.append(lpath)
+                # remove processed files from the remote dict
+                # after processing only old files will be letf there
+                rdict.pop(lname)
+            else:
+                new.append(lpath)
+
+        return rdict.keys(), not_changed, changed, new
+
+    @msger.waiting
+    def commit_files(self, prj, pkg, files, message):
+        """Commits files to OBS."""
+
+        query = {'cmd'    : 'commitfilelist',
+                 'user'   : conf.get_apiurl_usr(self.apiurl),
+                 'comment': message}
+        url = core.makeurl(self.apiurl, ['source', prj, pkg], query=query)
+
+        xml = "<directory>"
+        for fpath, _ in files:
+            with open(fpath) as fhandle:
+                xml += '<entry name="%s" md5="%s"/>' % \
+                       (os.path.basename(fpath), hexdigest(fhandle))
+        xml += "</directory>"
+
+        try:
+            self.core_http(core.http_POST, url, data=xml)
+            for fpath, commit_flag in files:
+                if commit_flag:
+                    put_url = core.makeurl(
+                        self.apiurl, ['source', prj, pkg,
+                                      pathname2url(os.path.basename(fpath))],
+                        query="rev=repository")
+                    self.core_http(core.http_PUT, put_url, filep=fpath)
+            self.core_http(core.http_POST, url, data=xml)
+        except OSCError, err:
+            raise ObsError("can't commit files to %s/%s: %s" % (prj, pkg, err))
+
+    @msger.waiting
+    def remove_files(self, prj, pkg, fnames=None):
+        """
+        Remove file[s] from the package.
+        If filenames are not provided remove all files.
+        """
+        if not fnames:
+            url = core.makeurl(self.apiurl, ['source', prj, pkg])
+            for i in (1, 2, 3):
+                try:
+                    response = self.core_http(core.http_GET, url).read()
+                    entries = core.ET.fromstring(response)
+                    break
+                except OSCError, err:
+                    raise ObsError("can't get list of sources from"\
+                                   " %s/%s: %s" % (prj, pkg, err))
+                except core.ET.ParseError, err:
+                    if i == 3:
+                        raise ObsError("Error parsing OBS response: %s" \
+                                       % str(err))
+                    continue
+
+            fnames = [entry.get('name') for entry in entries]
+
+        for fname in fnames:
+            if fname is None:
+                continue
+            query = 'rev=upload'
+            url = core.makeurl(self.apiurl,
+                               ['source', prj, pkg, pathname2url(fname)],
+                               query=query)
+            try:
+                self.core_http(core.http_DELETE, url)
+            except OSCError, err:
+                raise ObsError("can\'t remove file %s/%s/%s: %s" \
+                               % (prj, pkg, fname, err))
+
+    def create_package(self, prj, pkg):
+        """Create package in the project."""
+
+        meta = '<package project="%s" name="%s">'\
+               '<title/><description/></package>' % (prj, pkg)
+        url = core.make_meta_url("pkg", (quote_plus(prj), quote_plus(pkg)),
+                                 self.apiurl, False)
+        try:
+            self.core_http(core.http_PUT, url, data=meta)
+        except OSCError, err:
+            raise ObsError("can't create %s/%s: %s" % (prj, pkg, err))
+
+    def get_results(self, prj, pkg):
+        """Get package build results."""
+        results = defaultdict(dict)
+        try:
+            build_status = core.get_results(self.apiurl, prj, pkg)
+        except (urllib2.URLError, M2Crypto.m2urllib2.URLError,
+                M2Crypto.SSL.SSLError), err:
+            raise ObsError("can't get %s/%s build results: %s" \
+                           % (prj, pkg, str(err)))
+
+        for res in build_status:
+            repo, arch, status = res.split()
+            results[repo][arch] = status
+        return results
+
+    def get_buildlog(self, prj, pkg, repo, arch):
+        """Get package build log from OBS."""
+
+        url = core.makeurl(self.apiurl, ['build', prj, repo, arch, pkg,
+                                         '_log?nostream=1&start=0'])
+        try:
+            log = self.core_http(core.http_GET, url).read()
+        except OSCError, err:
+            raise ObsError("can't get %s/%s build log: %s" % (prj, pkg, err))
+
+        return log.translate(None, "".join([chr(i) \
+                                            for i in range(10) + range(11,32)]))
diff --git a/gitbuildsys/parsing.py b/gitbuildsys/parsing.py
new file mode 100644 (file)
index 0000000..776d44c
--- /dev/null
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""Local additions to commandline parsing."""
+
+import os
+import re
+import functools
+
+from argparse import RawDescriptionHelpFormatter, ArgumentTypeError
+
+class GbsHelpFormatter(RawDescriptionHelpFormatter):
+    """Changed default argparse help output by request from cmdln lovers."""
+
+    def __init__(self, *args, **kwargs):
+        super(GbsHelpFormatter, self).__init__(*args, **kwargs)
+        self._aliases = {}
+
+    def add_argument(self, action):
+        """Collect aliases."""
+
+        if action.choices:
+            for item, parser in action.choices.iteritems():
+                self._aliases[str(item)] = parser.get_default('alias')
+
+        return super(GbsHelpFormatter, self).add_argument(action)
+
+    def format_help(self):
+        """
+        There is no safe and documented way in argparse to reformat
+        help output through APIs as almost all of them are private,
+        so this method just parses the output and changes it.
+        """
+        result = []
+        subcomm = False
+        for line in super(GbsHelpFormatter, self).format_help().split('\n'):
+            if line.strip().startswith('{'):
+                continue
+            if line.startswith('optional arguments:'):
+                line = 'Global Options:'
+            if line.startswith('usage:'):
+                line = "Usage: gbs [GLOBAL-OPTS] SUBCOMMAND [OPTS]"
+            if subcomm:
+                match = re.match("[ ]+([^ ]+)[ ]+(.+)", line)
+                if match:
+                    name, help_text  = match.group(1), match.group(2)
+                    alias = self._aliases.get(name) or ''
+                    if alias:
+                        alias = "(%s)" % alias
+                    line = "  %-22s%s" % ("%s %s" % (name, alias), help_text)
+            if line.strip().startswith('subcommands:'):
+                line = 'Subcommands:'
+                subcomm = True
+            result.append(line)
+        return '\n'.join(result)
+
+def subparser(func):
+    """Convenient decorator for subparsers."""
+    @functools.wraps(func)
+    def wrapper(parser):
+        """
+        Create subparser
+        Set first line of function's docstring as a help
+        and the rest of the lines as a description.
+        Set attribute 'module' of subparser to 'cmd'+first part of function name
+        """
+        splitted = func.__doc__.split('\n')
+        name = func.__name__.split('_')[0]
+        subpar = parser.add_parser(name, help=splitted[0],
+                                   description='\n'.join(splitted[1:]),
+                                   formatter_class=RawDescriptionHelpFormatter)
+        subpar.set_defaults(module="cmd_%s" % name)
+        return func(subpar)
+    return wrapper
+
+
+def basename_type(path):
+    '''validate function for base file name argument'''
+    if os.path.basename(path) != path:
+        raise ArgumentTypeError('should be a file name rather than a path')
+    return path
diff --git a/gitbuildsys/runner.py b/gitbuildsys/runner.py
new file mode 100644 (file)
index 0000000..7ba98c2
--- /dev/null
@@ -0,0 +1,99 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+import subprocess
+
+from gitbuildsys import msger
+
+def runtool(cmdln_or_args, catch=1):
+    """ wrapper for most of the subprocess calls
+    input:
+        cmdln_or_args: can be both args and cmdln str (shell=True)
+        catch: 0, quitely run
+               1, only STDOUT
+               2, only STDERR
+               3, both STDOUT and STDERR
+    return:
+        (rc, output)
+        if catch==0: the output will always None
+    """
+
+    if catch not in (0, 1, 2, 3):
+        # invalid catch selection, will cause exception, that's good
+        return None
+
+    if isinstance(cmdln_or_args, list):
+        cmd = cmdln_or_args[0]
+        shell = False
+    else:
+        import shlex
+        cmd = shlex.split(cmdln_or_args)[0]
+        shell = True
+
+    dev_null = os.open("/dev/null", os.O_WRONLY)
+    sout = [dev_null, subprocess.PIPE, dev_null, subprocess.PIPE][catch]
+    serr = [dev_null, dev_null, subprocess.PIPE, subprocess.STDOUT][catch]
+
+    try:
+        process = subprocess.Popen(cmdln_or_args, stdout=sout,
+                             stderr=serr, shell=shell)
+        out = process.communicate()[0]
+        if out is None:
+            out = ''
+    except OSError, exc:
+        if exc.errno == 2:
+            # [Errno 2] No such file or directory
+            msger.error('Cannot run command: %s, lost dependency?' % cmd)
+        else:
+            raise # relay
+    finally:
+        os.close(dev_null)
+
+    return (process.returncode, out)
+
+def show(cmdln_or_args):
+    # show all the message using msger.verbose
+
+    rcode, out = runtool(cmdln_or_args, catch=3)
+
+    if isinstance(cmdln_or_args, list):
+        cmd = ' '.join(cmdln_or_args)
+    else:
+        cmd = cmdln_or_args
+
+    msg =  'running command: "%s"' % cmd
+    if out:
+        out = out.strip()
+    if out:
+        msg += ', with output::'
+        msg += '\n  +----------------'
+        for line in out.splitlines():
+            msg += '\n  | %s' % line
+        msg += '\n  +----------------'
+
+    msger.verbose(msg)
+    return rcode
+
+def outs(cmdln_or_args, catch=1):
+    # get the outputs of tools
+    return runtool(cmdln_or_args, catch)[1].strip()
+
+def quiet(cmdln_or_args):
+    return runtool(cmdln_or_args, catch=0)[0]
+
diff --git a/gitbuildsys/safe_url.py b/gitbuildsys/safe_url.py
new file mode 100644 (file)
index 0000000..c1a9f6c
--- /dev/null
@@ -0,0 +1,107 @@
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2012 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""
+This module provides a class SafeURL which can contain url/user/password read
+from config file, and hide plain user and password when it print to screen
+"""
+
+import urllib
+import urlparse
+
+
+class SafeURL(str):
+
+    '''SafeURL can hide user info when it's printed to console.
+    Use property full to get url with user info
+    '''
+
+    def __new__(cls, url, user=None, passwd=None):
+        safe_url, inline_user, inline_passwd = SafeURL._extract_userinfo(url)
+
+        inst = super(SafeURL, cls).__new__(cls, safe_url)
+
+        inst.user, inst.passwd = SafeURL._check_userinfo(inline_user,
+                                                         inline_passwd,
+                                                         user, passwd)
+        inst.components = urlparse.urlsplit(safe_url)
+        return inst
+
+    @property
+    def full(self):
+        '''return the full url with user and password'''
+        if self.is_local():
+            return self
+
+        userinfo = self._get_userinfo()
+        hostport = self._get_hostport(self.components)
+
+        if userinfo:
+            login = '%s@%s' % (userinfo, hostport)
+        else:
+            login = hostport
+
+        new_components = list(self.components)
+        new_components[1] = login
+        return urlparse.urlunsplit(new_components)
+
+    def is_local(self):
+        'return True is it is local path'
+        return self.startswith('/')
+
+    def pathjoin(self, *args):
+        '''treat self as path and urljoin'''
+        new = urlparse.urljoin(self.rstrip('/') + '/', *args)
+        return SafeURL(new, self.user, self.passwd)
+
+    def _get_userinfo(self):
+        '''return userinfo component of url'''
+        if not self.user:
+            return ''
+
+        escape = lambda raw: urllib.quote(raw, safe='')
+        return '%s:%s' % (escape(self.user), escape(self.passwd)) \
+            if self.passwd else escape(self.user)
+
+    @staticmethod
+    def _extract_userinfo(url):
+        '''strip inline user/password from url'''
+        results = urlparse.urlsplit(url)
+        hostport = SafeURL._get_hostport(results)
+
+        components = list(results)
+        components[1] = hostport
+        safe_url = urlparse.urlunsplit(components)
+
+        return safe_url, results.username, results.password
+
+    @staticmethod
+    def _get_hostport(components):
+        '''return hostport component from urlsplit result'''
+        if components.port:
+            return '%s:%d' % (components.hostname, components.port)
+        return components.hostname
+
+    @staticmethod
+    def _check_userinfo(user_inline, passwd_inline, user, passwd):
+        '''returns the valid user and passwd'''
+        user = user_inline or user
+        passwd = passwd_inline or passwd
+
+        if not user and passwd:
+            raise ValueError('No user is specified only password')
+        return user, passwd
diff --git a/gitbuildsys/utils.py b/gitbuildsys/utils.py
new file mode 100644 (file)
index 0000000..ac7a775
--- /dev/null
@@ -0,0 +1,540 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+import glob
+import tempfile
+import shutil
+import pycurl
+import hashlib
+import fnmatch
+import signal
+import subprocess
+import xml.etree.ElementTree as ET
+from collections import defaultdict
+
+from gitbuildsys import errors, msger
+
+from gbp.rpm.git import GitRepositoryError
+from gbp.errors import GbpError
+
+
+class Workdir(object):
+    def __init__(self, path):
+        self._newdir = path
+        self._cwd = os.getcwd()
+
+    def __enter__(self):
+        os.chdir(self._newdir)
+
+    def __exit__(self, _type, _value, _tb):
+        os.chdir(self._cwd)
+
+def guess_spec(git_path, packaging_dir, given_spec, commit_id='WC.UNTRACKED'):
+    '''guess spec file from project name if not given'''
+    git_path = os.path.abspath(git_path)
+
+    if commit_id == 'WC.UNTRACKED':
+        check = lambda fname: os.path.exists(os.path.join(git_path, fname))
+        glob_ = lambda pattern: [ name.replace(git_path+'/', '')
+            for name in glob.glob(os.path.join(git_path, pattern)) ]
+        msg = 'No such spec file %s'
+    else:
+        check = lambda fname: file_exists_in_rev(git_path, fname, commit_id)
+        glob_ = lambda pattern: glob_in_rev(git_path, pattern, commit_id)
+        msg = "No such spec file %%s in %s" % commit_id
+
+    if given_spec:
+        spec = os.path.join(packaging_dir, given_spec)
+        if not check(spec):
+            msger.error(msg % spec)
+        return spec
+
+    specs = glob_(os.path.join(packaging_dir, '*.spec'))
+    if not specs:
+        msger.error("can't find any spec file")
+
+    project_name =  os.path.basename(git_path)
+    spec = os.path.join(packaging_dir, '%s.spec' % project_name)
+    return spec if spec in specs else specs[0]
+
+
+class Temp(object):
+    """
+    Create temporary file or directory.
+    Delete it automatically when object is destroyed.
+
+    """
+
+    def __init__(self, suffix='', prefix='tmp', dirn=None,
+                 directory=False, content=None):
+        """
+        Create file or directory using tempfile.mk[sd]temp.
+        If content is provided write it to the file.
+
+        """
+        self.directory = directory
+        self.path = None
+
+        try:
+            if dirn:
+                target_dir = os.path.abspath(os.path.join(dirn, prefix))
+            else:
+                target_dir = os.path.abspath(prefix)
+            target_dir = os.path.dirname(target_dir)
+
+            if not os.path.exists(target_dir):
+                os.makedirs(target_dir)
+
+            if directory:
+                path = tempfile.mkdtemp(suffix, prefix, dirn)
+            else:
+                (fds, path) = tempfile.mkstemp(suffix, prefix, dirn)
+                os.close(fds)
+                if content:
+                    with file(path, 'w+') as fobj:
+                        fobj.write(content)
+        except OSError, err:
+            raise errors.GbsError("Failed to create dir or file on %s: %s" % \
+                            (target_dir, str(err)))
+        self.path = path
+
+    def __del__(self):
+        """Remove it when object is destroyed."""
+        if self.path and os.path.exists(self.path):
+            if self.directory:
+                shutil.rmtree(self.path, True)
+            else:
+                os.unlink(self.path)
+
+class TempCopy(object):
+    """Copy original file to temporary file in the same directory as
+       original. Creates empty temporary file if original doesn't exist.
+       Deletes temporary file when object is destroyed.
+    """
+
+    def __init__(self, content=None):
+        tmpffd, self.name = tempfile.mkstemp()
+        os.close(tmpffd)
+
+        if content:
+            with open(self.name, 'w') as fobj:
+                fobj.write(content)
+
+        self.stat = os.stat(self.name)
+
+    def update_stat(self):
+        """Updates stat info."""
+        self.stat = os.stat(self.name)
+
+    def is_changed(self):
+        """Check if temporary file has been changed."""
+        return os.stat(self.name) != self.stat
+
+    def __del__(self):
+        if os.path.exists(self.name):
+            os.unlink(self.name)
+
+
+class PageNotFound(errors.UrlError):
+    'page not found error: 404'
+
+class URLGrabber(object):
+    '''grab an url and save to local file'''
+
+    def __init__(self, connect_timeout=30):
+        '''create Curl object and set one-time options'''
+        curl = pycurl.Curl()
+        curl.setopt(pycurl.FAILONERROR, True)
+        curl.setopt(pycurl.FOLLOWLOCATION, True)
+        curl.setopt(pycurl.SSL_VERIFYPEER, False)
+        curl.setopt(pycurl.SSL_VERIFYHOST, False)
+        curl.setopt(pycurl.CONNECTTIMEOUT, connect_timeout)
+        #curl.setopt(pycurl.VERBOSE, 1)
+        self.curl = curl
+
+    def change_url(self, url, outfile, user, passwd):
+        '''change options for individual url'''
+
+        curl = self.curl
+        curl.url = url
+        curl.setopt(pycurl.URL, url)
+        curl.setopt(pycurl.WRITEDATA, outfile)
+        if user:
+            userpwd = user
+            if passwd:
+                userpwd = '%s:%s' % (user, passwd)
+            curl.setopt(pycurl.USERPWD, userpwd)
+
+    def perform(self):
+        '''do the real Curl perform work'''
+
+        curl = self.curl
+
+        stop = [False]
+        def progressing(*_args):
+            '''Returning a non-zero value from this callback will cause libcurl
+            to abort the transfer and return CURLE_ABORTED_BY_CALLBACK.'''
+            return -1 if stop[0] else 0
+
+        def handler(_signum, _frame):
+            '''set stop flag if catch SIGINT,
+            if not catch SIGINT, pycurl will print traceback'''
+            stop[0] = True
+
+        curl.setopt(pycurl.PROGRESSFUNCTION, progressing)
+        curl.setopt(pycurl.NOPROGRESS, False)
+        original_handler = signal.signal(signal.SIGINT, handler)
+
+        try:
+            curl.perform()
+        except pycurl.error, err:
+            msger.debug('fetching error:%s' % str(err))
+
+            errcode, errmsg = err.args
+            http_code = curl.getinfo(pycurl.HTTP_CODE)
+
+            if errcode == pycurl.E_OPERATION_TIMEOUTED:
+                raise errors.UrlError("connect timeout to %s, maybe it's "
+                                      "caused by proxy settings, please "
+                                      "check." % curl.url)
+            elif errcode == pycurl.E_ABORTED_BY_CALLBACK:
+                raise KeyboardInterrupt(err)
+            elif http_code in (401, 403):
+                raise errors.UrlError('authenticate failed on: %s' % curl.url)
+            elif http_code == 404:
+                raise PageNotFound(err)
+            else:
+                raise errors.UrlError('URL error on %s: (%s: "%s")' %
+                                     (curl.url, errcode, errmsg))
+        finally:
+            signal.signal(signal.SIGINT, original_handler)
+
+    def __del__(self):
+        '''close Curl object'''
+        self.curl.close()
+        self.curl = None
+
+    def grab(self, url, filename, user=None, passwd=None):
+        '''grab url to filename'''
+
+        msger.debug("fetching %s => %s" % (url, filename))
+
+        with open(filename, 'w') as outfile:
+            self.change_url(url, outfile, user, passwd)
+            self.perform()
+
+
+class RepoParser(object):
+    """ Repository parser for generate real repourl and build config
+    """
+
+    def __init__(self, repos, cachedir):
+        self.cachedir = cachedir
+        self.repourls  = defaultdict(list)
+        self.buildconf = None
+        self.standardrepos = []
+        self.urlgrabber = URLGrabber()
+
+        self.localrepos, remotes = self.split_out_local_repo(repos)
+        self.parse(remotes)
+
+    @staticmethod
+    def _parse_build_xml(build_xml):
+        '''parse build.xml returns a dict contains buildconf, repos and archs'''
+        if not (build_xml and os.path.exists(build_xml)):
+            return
+
+        try:
+            etree = ET.parse(build_xml)
+        except ET.ParseError:
+            msger.warning('Not well formed xml: %s' % build_xml)
+            return
+
+        meta = {}
+        root = etree.getroot()
+
+        buildelem = root.find('buildconf')
+        # Must using None here, "if buildelem" is wrong
+        # None means item does not exist
+        # It's different from bool(buildelem)
+        if buildelem is not None:
+            meta['buildconf'] = buildelem.text.strip()
+
+        repo_items = root.find('repos')
+        if repo_items is not None:
+            meta['repos'] = [ repo.text.strip()
+                             for repo in repo_items.findall('repo') ]
+
+        arch_items = root.find('archs')
+        if arch_items is not None:
+            meta['archs'] = [ arch.text.strip()
+                             for arch in arch_items.findall('arch') ]
+        id_item = root.find('id')
+        if id_item is not None:
+            meta['id'] = id_item.text.strip()
+
+        return meta
+
+    def build_repos_from_buildmeta(self, baseurl, meta):
+        '''parse build.xml and pickup standard repos it contains'''
+        archs = meta.get('archs', [])
+        repos = meta.get('repos', [])
+
+        for arch in archs:
+            for repo in repos:
+                repourl = baseurl.pathjoin('repos/%s/%s/packages' % (repo,
+                                                                     arch))
+                if self.is_standard_repo(repourl):
+                    self.repourls[arch].append(repourl)
+
+    def fetch(self, url):
+        '''return file name if fetch url success, else None'''
+        fname = os.path.join(self.cachedir, os.path.basename(url))
+
+        try:
+            self.urlgrabber.grab(url, fname, url.user, url.passwd)
+        except PageNotFound:
+            return
+
+        return fname
+
+    def is_standard_repo(self, repo):
+        '''Check if repo is standard repo with repodata/repomd.xml exist'''
+
+        repomd_url = repo.pathjoin('repodata/repomd.xml')
+        return not not self.fetch(repomd_url)
+
+    def _fetch_build_meta(self, latest_repo_url):
+        '''fetch build.xml and parse'''
+        buildxml_url = latest_repo_url.pathjoin('builddata/build.xml')
+        build_xml = self.fetch(buildxml_url)
+        if build_xml:
+            return self._parse_build_xml(build_xml)
+
+    def _fetch_build_conf(self, latest_repo_url, meta):
+        '''fetch build.conf whose file name is get from build.xml'''
+        if self.buildconf:
+            return
+
+        if not meta or \
+            'buildconf' not in meta or \
+            not meta['buildconf']:
+            msger.warning("No build.conf in build.xml "
+                          "of repo: %s" % latest_repo_url)
+            return
+
+        buildconf_url = latest_repo_url.pathjoin('builddata/%s' %
+                                                 meta['buildconf'])
+        fname = self.fetch(buildconf_url)
+        if fname:
+            release, _buildid = meta['id'].split('_')
+            release = release.replace('-','')
+            target_conf = os.path.join(os.path.dirname(fname),
+                                       '%s.conf' % release)
+            os.rename(fname, target_conf)
+            self.buildconf = target_conf
+
+    def parse(self, remotes):
+        '''parse each remote repo, try to fetch build.xml and build.conf'''
+        def deal_with_one_repo(repo):
+            'deal with one repo url'
+            if self.is_standard_repo(repo):
+                self.standardrepos.append(repo)
+
+                if self.buildconf:
+                    return
+
+                latest_repo_url = repo.pathjoin('../../../../')
+                if latest_repo_url.find('../') >= 0:
+                    return
+                meta = self._fetch_build_meta(latest_repo_url)
+                if meta:
+                    self._fetch_build_conf(latest_repo_url, meta)
+                return
+
+            # Check if it's repo with builddata/build.xml exist
+            meta = self._fetch_build_meta(repo)
+            if meta:
+                # Generate repos from build.xml
+                self.build_repos_from_buildmeta(repo, meta)
+                self._fetch_build_conf(repo, meta)
+
+        for repo in remotes:
+            deal_with_one_repo(repo)
+
+    @staticmethod
+    def split_out_local_repo(repos):
+        '''divide repos into two parts, local and remote'''
+        local_repos = []
+        remotes = []
+
+        for repo in repos:
+            if repo.is_local():
+                if os.path.exists(repo):
+                    local_repos.append(repo)
+                else:
+                    msger.warning('No such repo path:%s' % repo)
+            else:
+                remotes.append(repo)
+
+        return local_repos, remotes
+
+    def get_repos_by_arch(self, arch):
+        '''get repos by arch'''
+        repos = self.localrepos + self.standardrepos # local repos first
+
+        if arch in ['ia32', 'i686', 'i586']:
+            arch = 'ia32'
+        if self.repourls and arch in self.repourls:
+            repos.extend(self.repourls[arch])
+
+        def filter_valid_repo(repos):
+            'filter valid remote and local repo'
+            rets = []
+            for url in repos:
+                if not url.startswith('http://') and \
+                    not url.startswith('https://') and \
+                    not (url.startswith('/') and os.path.exists(url)):
+                    msger.warning('ignore invalid repo url: %s' % url)
+                else:
+                    rets.append(url)
+            return rets
+
+        return filter_valid_repo(repos)
+
+
+def git_status_checker(git, opts):
+    try:
+        if opts.commit:
+            git.rev_parse(opts.commit)
+        is_clean = git.is_clean()[0]
+        status = git.status()
+    except (GbpError, GitRepositoryError), err:
+        msger.error(str(err))
+
+    untracked_files = status['??']
+    uncommitted_files = []
+    for stat in status:
+        if stat == '??':
+            continue
+        uncommitted_files.extend(status[stat])
+
+    if not is_clean and not opts.include_all:
+        if untracked_files:
+            msger.warning('the following untracked files would NOT be '\
+                       'included:\n   %s' % '\n   '.join(untracked_files))
+        if uncommitted_files:
+            msger.warning('the following uncommitted changes would NOT be '\
+                       'included:\n   %s' % '\n   '.join(uncommitted_files))
+        msger.warning('you can specify \'--include-all\' option to '\
+                      'include these uncommitted and untracked files.')
+    if not is_clean and opts.include_all:
+        if untracked_files:
+            msger.info('the following untracked files would be included'  \
+                       ':\n   %s' % '\n   '.join(untracked_files))
+        if uncommitted_files:
+            msger.info('the following uncommitted changes would be included'\
+                       ':\n   %s' % '\n   '.join(uncommitted_files))
+
+def hexdigest(fhandle, block_size=4096):
+    """Calculates hexdigest of file content."""
+    md5obj = hashlib.new('md5')
+    while True:
+        data = fhandle.read(block_size)
+        if not data:
+            break
+        md5obj.update(data)
+    return md5obj.hexdigest()
+
+
+def show_file_from_rev(git_path, relative_path, commit_id):
+    '''return a single file content from given rev.'''
+
+    cmd = 'cd %s; git show %s:%s' % (git_path, commit_id, relative_path)
+    try:
+        return subprocess.check_output(cmd, shell=True)
+    except (subprocess.CalledProcessError, OSError), err:
+        msger.debug('failed to checkout %s from %s:%s' % (relative_path,
+                                                          commit_id, str(err)))
+    return None
+
+
+def file_exists_in_rev(git_path, relative_path, commit_id):
+    '''return True if file exists in given rev'''
+
+    cmd = 'cd %s; git ls-tree --name-only %s %s' % (
+        git_path, commit_id, relative_path)
+
+    try:
+        output = subprocess.check_output(cmd, shell=True)
+    except (subprocess.CalledProcessError, OSError), err:
+        raise errors.GbsError('failed to check existence of %s in %s:%s' % (
+            relative_path, commit_id, str(err)))
+
+    return output != ''
+
+
+def glob_in_rev(git_path, pattern, commit_id):
+    '''glob pattern in given rev'''
+
+    path = os.path.dirname(pattern)
+    cmd = 'cd %s; git ls-tree --name-only %s %s/' % (
+        git_path, commit_id, path)
+
+    try:
+        output = subprocess.check_output(cmd, shell=True)
+    except (subprocess.CalledProcessError, OSError), err:
+        raise errors.GbsError('failed to glob %s in %s:%s' % (
+            pattern, commit_id, str(err)))
+
+    return fnmatch.filter(output.splitlines(), pattern)
+
+
+def edit(initial_content=None):
+    '''
+    launch an editor to get input from user. return the content that input.
+    '''
+    from gitbuildsys.conf import configmgr
+    EDITOR = configmgr.get('editor') or os.getenv('EDITOR') or 'vi'
+
+    temp = TempCopy(initial_content)
+    subprocess.call('%s %s' % (EDITOR, temp.name), shell=True)
+
+    if temp.is_changed():
+        with open(temp.name) as fobj:
+            return fobj.read()
+    return ''
+
+
+def edit_file(target_fname, initial_content=None):
+    '''
+    create temporary copy of target_fname with initial_content, then launch an
+        editor, update content back if user do some changes.
+    return True if content has been changed.
+    '''
+    changes = edit(initial_content)
+    if not changes:
+        return False
+
+    try:
+        with open(target_fname, 'w') as fobj:
+            fobj.write(changes)
+    except IOError, err:
+        msger.error("Can't update %s: %s" % (target_fname, str(err)))
+    return True
diff --git a/packaging/Makefile b/packaging/Makefile
new file mode 100644 (file)
index 0000000..1539ac7
--- /dev/null
@@ -0,0 +1,17 @@
+PKG_NAME := gbs
+SPECFILE = $(addsuffix .spec, $(PKG_NAME))
+PKG_VERSION := $(shell grep '^Version: ' $(SPECFILE)|awk '{print $$2}')
+
+TARBALL := $(PKG_NAME)_$(PKG_VERSION).tar.gz
+
+dsc:tarball
+       @sed  -i 's/ [a-f0-9]\+ [0-9]\+ $(TARBALL)/ $(shell md5sum $(TARBALL) | sed "s/  / $(shell stat -c '%s' $(TARBALL)) /")/' $(PKG_NAME).dsc
+
+tarball:
+       @cd .. && git archive --prefix $(PKG_NAME)-$(PKG_VERSION)/ HEAD \
+               | gzip > packaging/$(TARBALL)
+
+clean:
+       @rm -f *.tar.gz
+
+all: clean tarball dsc
diff --git a/packaging/gbs.changes b/packaging/gbs.changes
new file mode 100644 (file)
index 0000000..400db3b
--- /dev/null
@@ -0,0 +1,206 @@
+* Mon Nov 26 12 2012 Qiang Zhang  <qiang.z.zhang@intel.com> - 0.12
+  * upgrade to gbs v0.12, which contains the following bug fixing & features:
+    * support build rpm packages for incremental build
+    * --noinit support
+    * x86_64 support
+    * add --keep-packs to keep unused packages in buildroot
+    * show simple progress message for long time operations
+    * pristine-tar support
+    * patches generation for upstream branch exists
+    * add --define option to define macros for rpmbuild
+    * no hard code default base project
+    * modify changelog order to follow default order of git log
+    * change --spec to use only base file name
+    * ignore .gbs.conf in patch-generation
+    * cmd_import: enable importing patches
+    * remove output repo and buildroot info to depanneur
+    * bug fix:
+      - set TIZEN_BUILD_ROOT as abspath
+
+* Mon Nov 12 2012 Qiang Zhang  <qiang.z.zhang@intel.com> - 0.11.1
+- Upgrade to gbs v0.11.1, which contains the following bug fixing & features:
+    * depend on depanneur 0.2.1 to fix build break issue for 'osc build'
+
+* Thu Oct 25 2012 Qiang Zhang  <qiang.z.zhang@intel.com> - 0.11
+- Upgrade to gbs v0.11, which contains the following bug fixing & features:
+    * Add --spec in 'gbs build' to support building one spec file for packages
+      contains multiple spec files.
+    * Add --profile/-P in 'gbs build' to support building packages using specified
+      profile.
+    * support local buildroot configurable in config file. The 'buildroot' can
+      be set under the 'general' section as a global setting.
+    * more clear and readable error report for gbs build, including gbs export
+      error, expansion error and rpmbuild error.
+    * bug fix:
+      - fix plaintext passwd printed for some error cases
+      - fix gbs archive tar ball issue if using user defined macro in spec file
+      - fix request passwd again if one package build for a long time(>15 mins)
+      - fix sudo timeout issue, which will result in endless loop
+      - fix return 0 from depanneur even if error occurs
+      - unify display color of debug message in gbs and depanneur
+      - fix endless loop if package circle dependency exists
+      - fix gbs build error if '~' exist in build root path
+      - fix passwd conflict issue with multiple instance of 'gbs build'
+      - fix remotebuild can't run in sub-directory issue
+      - fix gbs build error with https_proxy trailing '/'
+      - fix gbs submit gives no error if there is no comment
+      - describe missing dependencies for gbs build
+      - support create project outside home:<user> if user have permission
+      - fix server's certificate traceback issue for gbs remotebuild
+
+* Tue Sep 18 2012 Qiang Zhang  <qiang.z.zhang@intel.com> - 0.10
+- Upgrade to gbs v0.10, which contains the following features:
+    * Re-designed gbs config format and parser to support multiple profile more flexible:
+      - Use profile oriented style of config
+      - Inherited config files supportted, three level support now: /etc/gbs.conf, ~/.gbs.conf
+        and $PWD/.gbs.conf
+    * integrate depanneur to gbs
+    * local full build support, including the following features:
+      - Multiple packages build
+      - Dependency build
+      - Parallel build
+      - Incremental build
+    * Patch/upstream tarball generation is enabled if "upstream" branch is found
+      - If "pristine-tar" branch is found, checkout the orig tarball using pristine-tar
+      - If "pristine-tar" branch is NOT found, generate the upstream tarball from a git tag matching the version
+      - If the "upstream" branch is NOT found, gbs/gbp uses the current logic
+    * If local repo specified, local repo is high priority when selecting packages
+    * Remove -A option for gbs chroot, and build root directory must be specified
+    * Code cleanup and refinements.
+    * bug fix.
+
+* Mon Aug 13 2012 Qiang Zhang  <qiang.z.zhang@intel.com> - 0.9
+- Upgrade to gbs v0.9, which contains the following features:
+  * Upgrade to gbs v0.9, which contains the following features:
+    * Re-designed gbs config format and parser to support multiple profile more flexible:
+      - Use profile oriented style of config
+      - Inherited config files supportted, three level support now: /etc/gbs.conf, ~/.gbs.conf
+        and $PWD/.gbs.conf
+    * integrate depanneur to gbs
+    * local full build support, including the following features:
+      - Multiple packages build
+      - Dependency build
+      - Parallel build
+      - Incremental build
+    * Patch/upstream tarball generation is enabled if "upstream" branch is found
+      - If "pristine-tar" branch is found, checkout the orig tarball using pristine-tar
+      - If "pristine-tar" branch is NOT found, generate the upstream tarball from a git tag matching the version
+      - If the "upstream" branch is NOT found, gbs/gbp uses the current logic
+    * If local repo specified, local repo is high priority when selecting packages
+    * Code cleanup and refinements.
+    * bug fix.
+
+* Mon Aug 13 2012 Qiang Zhang  <qiang.z.zhang@intel.com> - 0.9
+- Upgrade to gbs v0.9, which contains the following features:
+  - Fedora support
+  - update build to 2012-08-10 version, which including featurs:
+    - prefix each build log line with the second since build started
+    - other refinements
+  - --out for `gbs build` to copy generated RPMs to specified directory
+  - --source-rpm supported in export subcommand to generate source
+  - Introduce a Temp class to create/cleanup temp file and directory.
+  - Use more standard way to transfer repository user/pass to build scripts and hidden passwd in build.
+  - Code cleanup and refinements.
+  - bug fix.
+
+* Wed Aug  1 12 2012 Qiang Zhang  <qiang.z.zhang@intel.com> - 0.8.1
+- Upgrade to gbs v0.8.1, which contains the following features:
+  - new subcommand 'submit' added, which can be used for developers
+    to submit code to OBS for building
+
+* Thu Jul 12 2012 Qiang Zhang  <qiang.z.zhang@intel.com> - 0.8
+- Upgrade to gbs v0.8, which contains the following features:
+  - moving remotebuild temp build files to packaging dir
+  - moving build root to $tmpdir/$user/gbs-buildroot.$arch
+  - support building un-commit changes with --including-all opt
+  - support building special commit id or tag
+  - gbs chroot support, user can chroot to the buildroot, and make
+    build, it is useful for the big packages
+  - support custom location of configuration file, user can specify
+    different conf besides using ~/.gbs.conf using -c global option
+  - developer to be able to view 'gbs remotebuild' log and build 
+    status using gbs with --buildlog and status options
+  - --extra-packs supported for developer installing extra packages
+    to build root, for example: --extra-packs=zypper,vim , this is
+    very usefull for developer to make buildroot as a full development
+    envionment
+
+* Wed Jun 27 2012 Qiang Zhang  <qiang.z.zhang@intel.com> - 0.7.1
+- Upgrade to gbs v0.7.1, which contains the following features:
+  - download build conf from repos
+  - support new format of repo url, for example:
+    http://download.tizen.org/snapshots/trunk/latest/, which contains
+    builddata/build.xml metadata, and using this file different
+    archs repos can be built out, so user dont need update conf
+    if transfer build archs
+  - more error handling for conf module
+  - new -m option for gbs changelog to add new entry
+  - create one entry in gbs changelog
+
+* Wed Jun  6 2012 Qiang Zhang  <qiang.z.zhang@intel.com> - 0.7
+- Upgrade to gbs v0.7, which contains the following features:
+  - new subcommand support:
+    - gbs changelog   : generate changelog from git commits to
+      changelog file
+    - gbs submit : maintain the changelogs file, sanity check etc.
+    - gbs export : export git tree as tar ball, format of tar ball
+      is from spec file source tag
+  - bug fixing:
+  - enhancement:
+
+* Mon Jun  4 2012 Qiang Zhang  <qiang.z.zhang@intel.com> - 0.6.3
+- Update to gbs 0.6.3
+    - Add binfmt-support for arm build support fix arm build issue
+    - print the detail path of binaries RPM packages
+
+* Fri Jun  1 2012 Qiang Zhang  <qiang.z.zhang@intel.com> - 0.6.2
+- Add 0001-remove-extra-output-info.patch for gbs build
+- Add 0002-dont-need-sudo-before-gbs-build.patch
+
+* Sat May 12 2012 Qiang Zhang  <qiang.z.zhang@intel.com> - 0.6
+- Upgrade to gbs v0.6, which contains the following features:
+  - subcommand renamed:
+    - build => remotebuild
+    - localbuild => build
+  - Update tizen-1.0.conf to fix build issue for tizen.org repo
+  - Code clean up:
+    - remove useless data/build.sh
+    - remove _fall_to_shell related code
+  - Add --ccache and --incremental options for gbs 'build'
+  - fix default build server api issue.
+  - fix git archive issue for zip format
+  - more error handling support
+
+* Fri Apr 13 2012 Qiang Zhang  <qiang.z.zhang@intel.com> - 0.5
+- Upgrade to gbs v0.5, which contains the following features:
+  - arm local build supported on ubuntu 10.04/10.10
+  - use sudo to run localbuild to fix proxy issue while using
+    tsocks. examples: $ sudo tsocks gbs localbuild
+  - fix permission issue while parsing specfile.
+
+* Thu Apr  5 2012 Qiang Zhang  <qiang.z.zhang@intel.com> - 0.4
+- Upgrade to gbs v0.4, which contains the following features:
+  - gbs localbuild/build: more archive tar ball format support
+  - unittest added:
+    - gbs help unit test
+    - utils/guess_version for tar ball unit test
+    - spec file parser module unit test
+  - Add arch check for gbs local build
+  - Raise obs error if Base project is empty
+* Thu Mar 22 2012 Qiang Zhang  <qiang.z.zhang@intel.com> - 0.3
+- Upgrade to gbs v0.3, which contains the following features:
+  - gbs localbuild support
+  - gbs import support, which support importing src.rpm and spec
+  - gbs import_tar support
+  - gbs import-orig support, which can used to update packages
+  - more information can be avaliable from 'man gbs'
+
+* Fri Feb 10 2012 Qiang Zhang  <qiang.z.zhang@intel.com> - 0.2
+- Update to latest stable release version 2.0.
+  - New gbs build: build rpm package from git repository on OBS
+  - New build service module to interact with OBS
+  - New git module to wrap local git command
+
+* Thu Dec 01 2011 Jian-feng Ding <jian-feng.ding@intel.com> - 0.1
+- Initial import to tizen OBS
+
diff --git a/packaging/gbs.dsc b/packaging/gbs.dsc
new file mode 100644 (file)
index 0000000..c8acec1
--- /dev/null
@@ -0,0 +1,10 @@
+Format: 1.0
+Source: gbs
+Version: 0.12
+Binary: gbs
+Maintainer: Jian-feng Ding <jian-feng.ding@intel.com>
+Architecture: all
+Standards-Version: 3.7.1
+Build-Depends: debhelper (>= 4.0.0), python-dev
+Files:
+ 574996dfeeb001e70f20239a0e621daf 2457861 gbs_0.12.tar.gz
diff --git a/packaging/gbs.spec b/packaging/gbs.spec
new file mode 120000 (symlink)
index 0000000..3133620
--- /dev/null
@@ -0,0 +1 @@
+../distfiles/gbs.spec
\ No newline at end of file
diff --git a/setup.cfg b/setup.cfg
new file mode 100644 (file)
index 0000000..d0e0c4d
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,2 @@
+[nosetests]
+cover-package=gitbuildsys
index 5b9b1f2..ebecebc 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -1,55 +1,52 @@
 #!/usr/bin/env python
 
 import os, sys
+import glob
+import re
+
 from distutils.core import setup
+
 try:
     import setuptools
     # enable "setup.py develop", optional
 except ImportError:
     pass
 
-MOD_NAME = 'tizenpkg'
-
-version_path = 'VERSION'
+MOD_NAME = 'gitbuildsys'
+version_path = os.path.join(MOD_NAME, "__init__.py")
 if not os.path.isfile(version_path):
-    print 'No VERSION file in topdir, abort'
+    print 'No %s version file found' % version_path
     sys.exit(1)
 
-try:
-    # first line should be the version number
-    version = open(version_path).readline().strip()
-    if not version:
-        print 'VERSION file is invalid, abort'
-        sys.exit(1)
-
-    ver_file = open('%s/__version__.py' % MOD_NAME, 'w')
-    ver_file.write("VERSION = \"%s\"\n" % version)
-    ver_file.close()
-except IOError:
-    print 'WARNING: Cannot write version number file'
+content = open(version_path).read()
+match = re.search(r'^__version__\s*=\s*[\x22\x27]([^\x22\x27]+)[\x22\x27]',
+                  content, re.M)
+if match:
+    version = match.group(1)
+else:
+    print 'Unable to find version in %s' % version_path
+    sys.exit(1)
 
 # "--install-layout=deb" is required for pyver>2.5 in Debian likes
 if sys.version_info[:2] > (2, 5):
     if len(sys.argv) > 1 and 'install' in sys.argv:
         try:
             import platform
-            (dist, ver, id) = platform.linux_distribution()
-
             # for debian-like distros, mods will be installed to
             # ${PYTHONLIB}/dist-packages
-            if dist in ('debian', 'Ubuntu'):
+            if platform.linux_distribution()[0] in ('debian', 'Ubuntu'):
                 sys.argv.append('--install-layout=deb')
-        except:
+        except Exception:
             pass
 
-setup(name='tizenpkg',
+setup(name='gbs',
       version = version,
       description='The command line tools for Tizen package developers',
       author='Jian-feng Ding, Huaxu Wan',
       author_email='jian-feng.ding@intel.com, huaxu.wan@intel.com',
-      url='http://git.tizen.org/',
-      scripts=['tools/tizenpkg'],
-      packages=['tizenpkg'],
-      package_data={'tizenpkg': ['data/*']},
+      url='https://git.tizen.org/',
+      scripts=['tools/gbs'],
+      packages=[MOD_NAME],
+      data_files = [('/usr/share/gbs', glob.glob('data/*'))],
      )
 
diff --git a/tests/test_changelog.py b/tests/test_changelog.py
new file mode 100644 (file)
index 0000000..a44bcd3
--- /dev/null
@@ -0,0 +1,167 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2012 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""Functionality tests for gbs changelog."""
+
+import os
+import shutil
+import unittest
+import tempfile
+import imp
+import datetime
+import time
+
+from nose.tools import eq_, raises
+
+from gbp.git.repository import GitRepository
+
+GBS = imp.load_source("gbs", "./tools/gbs").main
+ENV = {}
+
+def set_editor(editor):
+    '''set editor'''
+    os.environ['EDITOR'] = editor
+
+def setup_module():
+    """One setup for all tests."""
+
+    ENV["cwd"] = os.getcwd()
+    tmp = tempfile.mkdtemp(prefix="test-gbs-changelog-")
+    shutil.copy('.gbs.conf', tmp)
+    os.chdir(tmp)
+    ENV["dir"] = tmp
+
+    # Create git repo
+    repo = GitRepository.create('.')
+    author = repo.get_author_info()
+    ENV["repo"] = repo
+    ENV["name"] = author.name
+    ENV["email"] = author.email
+
+    # Make 3 commits
+    for num in (1, 2, 3):
+        with open("file", "w") as fobj:
+            fobj.write("content %d" % num)
+        time.sleep(1) # Sleep to make commit timestamps differ
+        repo.add_files(repo.path, untracked=True)
+        repo.commit_files(files="file", msg="change %d" % num)
+
+    ENV["date"] = datetime.datetime.now().strftime("%a %b %d %Y")
+    commits = sorted(repo.get_commits(options=['--pretty=format:%at %H']),
+                     reverse=True)
+
+    ENV["commits"] = [item.split()[-1] for item in commits]
+
+def teardown_module():
+    """Cleanup test directory."""
+    shutil.rmtree(ENV["dir"])
+    os.chdir(ENV["cwd"])
+
+
+class TestChangelog(unittest.TestCase):
+    """Test help output of gbs commands"""
+
+    def __init__(self, method):
+        super(TestChangelog, self).__init__(method)
+        self.changes = 'packaging/test.changes'
+        self.spec = 'packaging/test.spec'
+
+    def setUp(self):
+        os.chdir(ENV["dir"])
+
+        # [Re]create packaging/test.spec
+        shutil.rmtree('packaging', ignore_errors=True)
+        os.mkdir('packaging')
+        open("packaging/test.spec", "w").close()
+
+        set_editor("sleep 1 && touch")
+
+    def test_new_changes(self):
+        """Test generating new .changes."""
+        eq_(GBS(argv=["gbs", "changelog"]), None)
+        eq_(open(self.changes).read(),
+            "* %s %s <%s> %s\n- change 3\n- change 2\n- change 1\n\n" % \
+            (ENV["date"], ENV["name"], ENV["email"], ENV["commits"][0][:7]))
+
+    def test_new_changes_with_content(self):
+        """Test generating new .changes with specific content."""
+        eq_(GBS(argv=["gbs", "changelog", "-m", "new .changes"]), None)
+        eq_(open(self.changes).read(),
+            "* %s %s <%s> %s\n- new .changes\n\n" % \
+            (ENV["date"], ENV["name"], ENV["email"], ENV["commits"][0][:7]))
+
+    def test_update_changes(self):
+        """Test updating existing .changes."""
+        # create test.changes
+        init = "* %s name <email@some.domain> %s\n- init\n\n" % \
+               (ENV["date"], ENV["commits"][-1][:7])
+        with open(self.changes, "w") as changes:
+            changes.write(init)
+
+        eq_(GBS(argv=["gbs", "changelog"]), None)
+        expected = "* %s %s <%s> %s\n- change 3\n- change 2\n\n" % \
+                   (ENV["date"], ENV["name"], ENV["email"],
+                    ENV["commits"][0][:7])
+        eq_(open(self.changes).read(), expected+init)
+
+    def test_since(self):
+        """Test --since command line option."""
+        eq_(GBS(argv=["gbs", "changelog", "--since", ENV["commits"][1]]), None)
+        eq_(open(self.changes).read(),
+            "* %s %s <%s> %s\n- change 3\n\n" % \
+            (ENV["date"], ENV["name"], ENV["email"], ENV["commits"][0][:7]))
+
+    @staticmethod
+    def test_not_updated():
+        """Test normal exit when changelog is not updated."""
+        set_editor("true")
+        eq_(GBS(argv=["gbs ", "changelog"]), None)
+
+    @staticmethod
+    @raises(SystemExit)
+    def test_no_new_changes():
+        """Test failure when no new changes can be generated."""
+        eq_(GBS(argv=["gbs", "changelog"]), None)
+        GBS(argv=["gbs", "changelog"])
+
+    @staticmethod
+    @raises(SystemExit)
+    def test_wrong_since():
+        """Test failure with wrong --since value."""
+        GBS(argv=["gbs", "changelog", "--since", "bla"])
+
+    @raises(SystemExit)
+    def test_non_existent_commit(self):
+        """Test failure with wrong commit id in the changelog."""
+        with open(self.changes, "w") as changes:
+            changes.write("* Wed Aug 22 2012 test <test@otctools.jf.intel.com> "
+                          "xxxxxx\n- change 3\n\n")
+        GBS(argv=["gbs", "changelog"])
+
+    @staticmethod
+    @raises(SystemExit)
+    def test_not_in_git_repository():
+        """Test failure when run not in git repo."""
+        os.chdir('..')
+        GBS(argv=["gbs", "changelog"])
+
+    @raises(SystemExit)
+    def test_no_spec(self):
+        """Test failure when there is not spec in packaging dir."""
+        os.unlink(self.spec)
+        GBS(argv=["gbs", "changelog"])
diff --git a/tests/test_config.py b/tests/test_config.py
new file mode 100644 (file)
index 0000000..f01ae82
--- /dev/null
@@ -0,0 +1,144 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2012 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""Functional tests for GBS config"""
+
+import os
+import unittest
+
+from mock import patch
+
+from gitbuildsys.errors import ConfigError
+import gitbuildsys.conf
+
+
+FILE_DIRNAME = os.path.dirname(os.path.abspath(__file__))
+
+
+class Fixture(object):
+    '''test fixture for testing config'''
+
+    PATH = os.path.join(FILE_DIRNAME, 'testdata', 'ini')
+
+    ETC = '/etc/gbs.conf'
+    HOME = '~/.gbs.conf'
+    PROJECT = '.gbs.conf'
+
+    def __init__(self, etc=None, home=None, project=None):
+        self.fake_files = {self.ETC: etc,
+                           self.HOME: home,
+                           self.PROJECT: project,
+                           }
+
+        self.real_exists = os.path.exists
+        self.real_abspath = os.path.abspath
+        self.real_expanduser = os.path.expanduser
+
+    def fake_exists(self, path):
+        '''return True if corresponding fixture specified'''
+        return bool(self.fake_files[path]) if path in self.fake_files \
+            else self.real_exists(path)
+
+    def fake_abspath(self, path):
+        '''return itself if it's match fixture name'''
+        return path if path in self.fake_files else self.real_abspath(path)
+
+    def fake_expanduser(self, path):
+        '''return itself if it's match fixture name'''
+        return path if path in self.fake_files else self.real_expanduser(path)
+
+    def fake_open(self, name, *args):
+        '''open corresponding fixture file and return'''
+        return open(os.path.join(self.PATH, self.fake_files[name])) \
+                    if name in self.fake_files \
+                    else open(name, *args)
+
+    def __call__(self, func):
+        '''decorator to setup fixtures'''
+        patchers = [
+            patch('gitbuildsys.conf.os.path.exists', self.fake_exists),
+            patch('gitbuildsys.conf.os.path.expanduser', self.fake_expanduser),
+            patch('gitbuildsys.conf.os.path.abspath', self.fake_abspath),
+            patch('ConfigParser.open', self.fake_open, create=True),
+            ]
+        for patcher in patchers:
+            func = patcher(func)
+        return func
+
+
+class ConfigGettingTest(unittest.TestCase):
+    '''TestCase for config'''
+
+    @staticmethod
+    def get(section, option):
+        '''get section.option from config'''
+        # configmgr is a global variable, reload to recreate it
+        # otherwise fixtures only take effect in the first time
+        reload(gitbuildsys.conf)
+        return gitbuildsys.conf.configmgr.get(option, section)
+
+    @Fixture(project='project1.ini')
+    def test_no_such_section(self):
+        '''test no such section'''
+        self.assertRaises(ConfigError,
+                          self.get, 'not_exists_section', 'key')
+
+    @Fixture(project='project1.ini')
+    def test_no_such_option(self):
+        '''test no such option'''
+        self.assertRaises(ConfigError,
+                          self.get, 'section', 'not_exists_option')
+
+    @Fixture(project='project1.ini')
+    def test_simple_get(self):
+        '''get value when one config file provides'''
+        self.assertEqual('projv2', self.get('section', 'proj_only_key'))
+
+    @Fixture(home='home1.ini', project='project1.ini')
+    def test_inherit(self):
+        '''value can be inherit from two levels'''
+        self.assertEqual('homev2', self.get('section', 'home_only_key'))
+
+    @Fixture(home='home1.ini', project='project1.ini')
+    def test_overwrite(self):
+        '''value can be overwrite if name is the same'''
+        self.assertEqual('projv1', self.get('section', 'common_key'))
+
+    @Fixture(home='home1.ini')
+    def test_default_value(self):
+        'test get hardcode default value '
+        self.assertEquals('/var/tmp', self.get('general', 'tmpdir'))
+
+    @Fixture(home='without_section_header.ini')
+    def test_invalid_ini(self):
+        'test invalid ini'
+        self.assertRaises(ConfigError, reload, gitbuildsys.conf)
+
+    @Fixture(home='invalid_continuation_line.ini')
+    def test_invalid_continuation_line(self):
+        'test invalid cointinuation line'
+        self.assertRaises(ConfigError, reload, gitbuildsys.conf)
+
+    @Fixture(home='interpolation.ini')
+    def test_interpolation(self):
+        'test interpolation is supported'
+        self.assertEquals('abc/def', self.get('remote', 'target'))
+
+
+if __name__ == '__main__':
+    unittest.main()
\ No newline at end of file
diff --git a/tests/test_help.py b/tests/test_help.py
new file mode 100644 (file)
index 0000000..8a94645
--- /dev/null
@@ -0,0 +1,50 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2012 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""Functionality tests for gbs help."""
+
+import unittest
+import imp
+
+from nose.tools import eq_
+
+GBS = imp.load_source("gbs", "./tools/gbs").main
+
+class TestHelp(unittest.TestCase):
+    """Test help output of gbs commands"""
+
+    @staticmethod
+    def test_subcommand_help():
+        """Test running gbs help with all possible subcommands."""
+        for sub in [ "build", "lb", "remotebuild", "rb", "changelog", "ch",
+                     "submit", "sr", "export", "ex", "import", "im",
+                     "chroot", "chr"]:
+
+            try:
+                print '>>>sub', sub
+                GBS(argv=["gbs", sub, "--help"])
+            except SystemExit, err:
+                eq_(err.code, 0)
+
+    @staticmethod
+    def test_help():
+        """Test running gbs --help and gbs help."""
+        try:
+            GBS(argv=["gbs", "--help"])
+        except SystemExit, err:
+            eq_(err.code, 0)
diff --git a/tests/test_import.py b/tests/test_import.py
new file mode 100644 (file)
index 0000000..db0b797
--- /dev/null
@@ -0,0 +1,163 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2012 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""Functionality tests of gbs import."""
+
+import os
+import shutil
+import unittest
+import tempfile
+import imp
+
+from functools import wraps
+
+from nose.tools import eq_, raises
+
+from gbp.git.repository import GitRepository
+
+GBS = imp.load_source("gbs", "./tools/gbs").main
+
+def with_data(fname):
+    """
+    Parametrized decorator for testcase methods.
+    Gets name of the directory or file in tests/testdata/
+    Copies it to the temporary working directory and
+    runs testcase method there.
+    Adds fname as a parameter for the testcase method
+
+    """
+    def decorator(func):
+        """Decorator itself."""
+        @wraps(func)
+        def wrapper(*args, **kwargs):
+            """Main functionality is here."""
+            obj = args[0] # TestCase object
+            # Copy required data(fname) to object temporary directory
+            fpath = os.path.join(obj.cdir, "./tests/testdata", fname)
+            if os.path.isdir(fpath):
+                shutil.copytree(fpath, os.path.join(obj.tmp, fname))
+            else:
+                shutil.copy(fpath, obj.tmp)
+            # Append fname to testcase method parameters
+            args = list(args)
+            args.append(fpath)
+            args = tuple(args)
+            return func(*args, **kwargs)
+        return wrapper
+    return decorator
+
+class TestImport(unittest.TestCase):
+    """Test help output of gbs commands"""
+
+    def __init__(self, method):
+        super(TestImport, self).__init__(method)
+
+    def setUp(self):
+        self.tmp = tempfile.mkdtemp(prefix="test-gbs-import-")
+        shutil.copy('.gbs.conf', self.tmp)
+        self.cdir = os.getcwd()
+        os.chdir(self.tmp)
+
+    def tearDown(self):
+        os.chdir(self.cdir)
+        shutil.rmtree(self.tmp)
+
+    @with_data("ail-0.2.29-2.3.src.rpm")
+    def test_import_srcrpm(self, srcrpm):
+        """Test importing from source rpm."""
+        eq_(GBS(argv=["gbs", "import", srcrpm]), None)
+        repo = GitRepository("./ail")
+        eq_(repo.get_local_branches(), ['master', 'pristine-tar', 'upstream'])
+        eq_(repo.get_tags(), ['upstream/0.2.29', 'vendor/0.2.29-2.3'])
+
+    @with_data("bluez_unpacked")
+    def test_import_spec(self, srcdir):
+        """Test importing from spec."""
+        eq_(GBS(argv=["gbs", "import",
+                      os.path.join(srcdir, 'bluez.spec')]), None)
+        repo = GitRepository("./bluez")
+        eq_(repo.get_local_branches(), ['master', 'pristine-tar', 'upstream'])
+        # No packging tag as patch-import fails
+        eq_(repo.get_tags(), ['upstream/4.87'])
+        eq_(len(repo.get_commits(until='master')), 2)
+
+        #raise Exception(os.listdir('./bluez'))
+
+    @with_data("ail-0.2.29-2.5.src.rpm")
+    def test_running_from_git_tree(self, srcrpm):
+        """Test running gbs import from git tree."""
+        # Create empty git repo
+        repo = GitRepository.create("./repo_dir")
+        os.chdir(repo.path)
+        eq_(GBS(argv=["gbs", "import", srcrpm]), None)
+        eq_(repo.get_local_branches(), ['master', 'pristine-tar', 'upstream'])
+        eq_(repo.get_tags(), ['upstream/0.2.29', 'vendor/0.2.29-2.5'])
+
+        #raise Exception(os.listdir('./bluez'))
+
+    @with_data("app-core-1.2-19.3.src.rpm")
+    def test_set_author_name_email(self, srcrpm):
+        """Test --author-name and --author-email command line options."""
+        eq_(GBS(argv=["gbs", "import", "--author-name=test",
+                      "--author-email=test@otctools.jf.intel.com",
+                      srcrpm]), None)
+        repo = GitRepository("./app-core")
+        eq_(repo.get_local_branches(), ['master', 'pristine-tar', 'upstream'])
+        eq_(repo.get_tags(), ['upstream/1.2', 'vendor/1.2-19.3'])
+
+    @with_data("ail-0.2.29-2.3.src.rpm")
+    def test_specify_upstream(self, srcrpm):
+        """Test --upstream command line option."""
+        eq_(GBS(argv=["gbs", "import", "--upstream=upstream",
+                      srcrpm]), None)
+        repo = GitRepository("./ail")
+        eq_(repo.get_local_branches(), ['master', 'pristine-tar', 'upstream'])
+        eq_(repo.get_tags(), ['upstream/0.2.29', 'vendor/0.2.29-2.3'])
+
+    @raises(SystemExit)
+    @with_data("bison-1.27.tar.gz")
+    def test_is_not_git_repository(self, tarball):
+        """Test raising exception when importing tarball outside of git."""
+        GBS(argv=["gbs", "import", tarball])
+
+    @raises(SystemExit)
+    @with_data("bad.src.rpm")
+    def test_error_reading_pkg_header(self, srcrpm):
+        """Test raising exception when importing from bad package."""
+        GBS(argv=["gbs", "import", srcrpm])
+
+    @raises(SystemExit)
+    @with_data("bad.spec")
+    def test_cant_parse_specfile(self, spec):
+        """Test raising exception when importing from non-parseable spec."""
+        GBS(argv=["gbs", "import", spec])
+
+    @raises(SystemExit)
+    def test_missing_argument(self):
+        """Test raising exception when running gbs without any arguments."""
+        GBS(argv=["gbs", "import"])
+
+    @raises(SystemExit)
+    def test_too_many_arguments(self):
+        """Test raising exception when running gbs with too many arguments."""
+        GBS(argv=["gbs", "import", "1", "2"])
+
+    @raises(SystemExit)
+    def test_path_doesnt_exist(self):
+        """Test raising exception when running gbs with not existing path."""
+        GBS(argv=["gbs", "import", "I don't exist!"])
diff --git a/tests/test_passwdx.py b/tests/test_passwdx.py
new file mode 100644 (file)
index 0000000..152f864
--- /dev/null
@@ -0,0 +1,173 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2012 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+"""Functional tests for setting passwdx back to config"""
+import unittest
+from StringIO import StringIO
+
+from mock import patch
+
+import gitbuildsys.conf
+from gitbuildsys.conf import BrainConfigParser
+from gitbuildsys.errors import ConfigError
+
+from test_config import Fixture
+
+
+class FakeFile(object):
+    'Fake file used to get updated config file'
+
+    def __init__(self):
+        self.buffer = StringIO()
+
+    def write(self, data):
+        'write data into fake file'
+        self.buffer.write(data)
+
+    def close(self):
+        'do not close buffer, then call getvalue() to retrieve the content'
+
+    def __exit__(self, *_args):
+        'mock with statement'
+
+    def __enter__(self):
+        'mock with statement'
+        return self
+
+    def getvalue(self):
+        'get content of fake file'
+        return self.buffer.getvalue()
+
+
+@patch('gitbuildsys.conf.open', create=True)
+class PasswdxTest(unittest.TestCase):
+    'Test for setting passwdx'
+
+    @Fixture(home='plain_passwd.ini')
+    def test_one_file(self, fake_open):
+        'test passwdx set back to one file'
+        conf = FakeFile()
+        fake_open.return_value = conf
+
+        reload(gitbuildsys.conf)
+
+        self.assertEquals('''[remotebuild]
+build_server = https://api
+passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
+
+[build]
+repo1.url = https://repo1
+repo1.passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
+''', conf.getvalue())
+
+
+    @Fixture(home='plain_passwd.ini', project='plain_passwd2.ini')
+    def test_two_files(self, fake_open):
+        'test passwdx set back to two files'
+        confs = [FakeFile(), FakeFile()]
+        def side_effect(name, _mode):
+            'fake open'
+            if name == '~/.gbs.conf':
+                return confs[0]
+            return confs[1]
+        fake_open.side_effect = side_effect
+
+        reload(gitbuildsys.conf)
+
+        self.assertEquals('''[remotebuild]
+build_server = https://api
+passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
+
+[build]
+repo1.url = https://repo1
+repo1.passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
+''', confs[0].getvalue())
+
+        self.assertEquals('''[remotebuild]
+build_server = https://api
+user = test
+passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
+
+[build]
+repo1.url = https://repo1
+repo1.user = test
+repo1.passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
+''', confs[1].getvalue())
+
+
+    @Fixture(home='normal_passwdx.ini')
+    def test_get_passwdx(self, _fake_open):
+        'test get decode passwd'
+        reload(gitbuildsys.conf)
+
+        pwd = gitbuildsys.conf.configmgr.get('passwd', 'remotebuild')
+        self.assertEquals('secret', pwd)
+
+    @Fixture(home='plain_passwd.ini')
+    def test_get_passwd(self, fake_open):
+        'test get decode passwd'
+        fake_open.return_value = FakeFile()
+
+        reload(gitbuildsys.conf)
+
+        pwd = gitbuildsys.conf.configmgr.get('passwd', 'remotebuild')
+        self.assertEquals('secret', pwd)
+
+    @Fixture(home='bad_passwdx.ini')
+    def test_bad_passwdx(self, _fake_open):
+        'test bad passwdx'
+        reload(gitbuildsys.conf)
+
+        self.assertRaises(ConfigError, gitbuildsys.conf.configmgr.get,
+                          'passwd', 'remotebuild')
+
+    @Fixture(home='empty_passwdx.ini')
+    def test_empty_passwdx(self, _fake_open):
+        'test empty passwdx'
+        reload(gitbuildsys.conf)
+
+        pwd = gitbuildsys.conf.configmgr.get('passwd', 'remotebuild')
+        self.assertEquals('', pwd)
+
+
+@patch('gitbuildsys.conf.os.chmod')
+@patch('gitbuildsys.conf.open', create=True)
+class AutoGenerateTest(unittest.TestCase):
+    'test auto generation if no conf was found'
+
+    @Fixture()
+    def test_auto_generate_conf(self, fake_open, _fake_chmod):
+        'test auto generate conf should contain obs and repos'
+        conf = FakeFile()
+        fake_open.return_value = conf
+
+        reload(gitbuildsys.conf)
+
+        parser = BrainConfigParser()
+        parser.readfp(StringIO(conf.getvalue()))
+
+        name = parser.get('general', 'profile')
+        obs = parser.get(name, 'obs')
+        repos = parser.get(name, 'repos')
+
+        self.assertTrue(parser.has_section(obs))
+        for repo in repos.split(','):
+            self.assertTrue(parser.has_section(repo.strip()))
+
+
+if __name__ == '__main__':
+    unittest.main()
\ No newline at end of file
diff --git a/tests/test_profile.py b/tests/test_profile.py
new file mode 100644 (file)
index 0000000..7d2719f
--- /dev/null
@@ -0,0 +1,210 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2012 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+"""Functional tests for profile style of config"""
+import unittest
+
+from mock import patch, MagicMock, Mock
+
+import gitbuildsys.conf
+from gitbuildsys.errors import ConfigError
+from test_config import Fixture
+from test_passwdx import FakeFile
+
+
+def get_profile():
+    '''get current profile to test'''
+    reload(gitbuildsys.conf)
+    return gitbuildsys.conf.configmgr.get_current_profile()
+
+
+class ProfileStyleTest(unittest.TestCase):
+    '''Test for profile oriented config'''
+
+    @Fixture(home='profile.ini')
+    def test_profile_api(self):
+        'test get obs api'
+        self.assertEquals('https://api.tz/path', get_profile().obs.url)
+
+    @Fixture(home='profile.ini')
+    def test_api_inherit_auth(self):
+        'test api can inherit auto from parent profile section'
+        self.assertEquals('https://Alice:secret@api.tz/path',
+                          get_profile().obs.url.full)
+
+    @Fixture(home='profile_only_has_api.ini')
+    def test_api_auth_can_be_overwrite(self):
+        'test api auth can be overwrite'
+        self.assertEquals('https://Bob:classified@api.tz/path',
+                          get_profile().obs.url.full)
+
+    @Fixture(home='profile.ini')
+    def test_profile_repos_in_order(self):
+        'repos must be in same order as they are write in config'
+        self.assertEquals(['https://repo/ia32/main',
+                           'https://repo/ia32/non-oss',
+                           'https://repo/ia32/base',
+                           '/local/path'],
+                          [i.url for i in get_profile().repos])
+
+    @Fixture(home='profile.ini')
+    def test_repo_inherit_auth(self):
+        'test repo can inherit auth from parent section'
+        self.assertEquals('https://Alice:secret@repo/ia32/main',
+                          get_profile().repos[0].url.full)
+
+    @Fixture(home='profile.ini')
+    def test_repo_overwrite_auth(self):
+        'test repo auth can be overwrite'
+        self.assertEquals('https://Bob:classified@repo/ia32/base',
+                          get_profile().repos[2].url.full)
+
+    @Fixture(home='bug387_inherit_only_user.ini')
+    def test_inherit_only_user(self):
+        'test inherit only user from parent'
+        self.assertEquals('https://tester:secret@repo',
+                          get_profile().repos[0].url.full)
+        self.assertEquals('https://tester:secret@obs',
+                          get_profile().obs.url.full)
+
+    @Fixture(home='bug387_inherit_only_passwdx.ini')
+    def test_inherit_only_passwdx(self):
+        'test inherit only password from parent'
+        self.assertEquals('https://tester:secret@repo',
+                          get_profile().repos[0].url.full)
+        self.assertEquals('https://tester:secret@obs',
+                          get_profile().obs.url.full)
+
+    @Fixture(home='bug387_only_password_no_user.ini')
+    def test_only_password_no_user(self):
+        'test only password no user'
+        self.assertRaises(ConfigError, get_profile)
+
+    @Fixture(home='bug387_inline_auth_has_the_highest_priority.ini')
+    def test_inline_highest_priority(self):
+        'test inline auth has the highest priority'
+        self.assertEquals('https://this:inline-pwd@obs',
+                          get_profile().obs.url.full)
+
+    @Fixture(home='no_such_profile_section_name.ini')
+    def test_no_such_profile(self):
+        'test profile name does not exist'
+        self.assertRaises(ConfigError, get_profile)
+
+    @Fixture(home='empty_profile.ini')
+    def test_empty_profile(self):
+        'test get a empty profile'
+        profile = get_profile()
+
+        self.assertEquals(None, profile.obs)
+        self.assertEquals([], profile.repos)
+
+    @Fixture(home='profile.ini')
+    def test_local_repo_need_not_auth(self):
+        '''test local path needn't auth info'''
+        self.assertEquals('/local/path', get_profile().repos[3].url.full)
+
+    @Fixture(home='profile.ini')
+    def test_obs_base_project(self):
+        'test read base project from conf'
+        self.assertEquals('base', get_profile().obs.base)
+
+    @Fixture(home='profile.ini')
+    def test_obs_target_project(self):
+        'test read target project from conf'
+        self.assertEquals('target', get_profile().obs.target)
+
+
+@patch('gitbuildsys.conf.open', MagicMock(), create=True)
+@patch('gitbuildsys.conf.os.rename', Mock())
+class SubcommandStyleTest(unittest.TestCase):
+    '''test for subcommand oriented config'''
+
+    @Fixture(home='subcommand.ini')
+    def test_api(self):
+        'test obs api'
+        self.assertEquals('https://api/build/server', get_profile().obs.url)
+
+    @Fixture(home='subcommand.ini')
+    def test_api_auth(self):
+        'test api auth'
+        self.assertEquals('https://Alice:secret@api/build/server',
+                          get_profile().obs.url.full)
+
+    @Fixture(home='subcommand.ini')
+    def test_repos_in_order(self):
+        'repos list must be in the same order as they are write in config'
+        self.assertEquals(['https://repo1/path',
+                           'https://repo2/path',
+                           '/local/path/repo'],
+                          [i.url for i in get_profile().repos])
+
+    @Fixture(home='subcommand.ini')
+    def test_repo_auth(self):
+        'test repo auth'
+        self.assertEquals('https://Alice:secret@repo1/path',
+                          get_profile().repos[0].url.full)
+
+
+
+@patch('gitbuildsys.conf.open', create=True)
+class ConvertTest(unittest.TestCase):
+    'Test convert subcommand to profile'
+
+    @Fixture(home='subcommand.ini')
+    def test_convert(self, fake_open):
+        'test convert'
+        conf = FakeFile()
+        fake_open.return_value = conf
+
+        get_profile()
+
+        self.assertEquals(conf.getvalue(), '''[general]
+profile = profile.current
+
+[obs.remotebuild]
+url = https://api/build/server
+user = Alice
+passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
+base_prj = Main
+target_prj = Target
+
+[repo.repo1]
+url = https://repo1/path
+user = Alice
+passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
+
+[repo.repo2]
+url = https://repo2/path
+user = Alice
+passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
+
+[repo.repo3]
+url = /local/path/repo
+
+[profile.current]
+obs = obs.remotebuild
+repos = repo.repo1, repo.repo2, repo.repo3
+
+''')
+
+
+
+
+
+if __name__ == '__main__':
+    unittest.main()
\ No newline at end of file
diff --git a/tests/test_safe_url.py b/tests/test_safe_url.py
new file mode 100644 (file)
index 0000000..26ea8b1
--- /dev/null
@@ -0,0 +1,106 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2012 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""Unit tests for class SafeURL"""
+
+import unittest
+
+from gitbuildsys.safe_url import SafeURL
+
+
+class SafeURLTest(unittest.TestCase):
+    '''Test SafeURL class'''
+
+    def test_passwd_no_user(self):
+        '''raise ValueError if only given password'''
+        self.assertRaises(ValueError, SafeURL, 'http://:password@server')
+
+    def test_password_no_user_by_arg(self):
+        '''raise ValueError if only given password'''
+        self.assertRaises(ValueError, SafeURL, 'http://server', None, 'passwd')
+
+    def test_both_user_and_password(self):
+        '''both user and passwd are given'''
+        url = SafeURL('http://server', 'Alice', 'password')
+
+        self.assertEqual('http://server', url)
+        self.assertEqual('http://Alice:password@server', url.full)
+
+    def test_only_user_no_password(self):
+        '''only user no password'''
+        url = SafeURL('http://Alice@server')
+
+        self.assertEqual('http://server', url)
+        self.assertEqual('http://Alice@server', url.full)
+
+    def test_no_user_and_no_password(self):
+        '''no user and no passwd'''
+        url = SafeURL('http://server')
+
+        self.assertEqual('http://server', url)
+        self.assertEqual(url, url.full)
+
+    def test_port(self):
+        '''port given'''
+        url = SafeURL('http://Alice:password@server:8080')
+
+        self.assertEqual('http://server:8080', str(url))
+        self.assertEqual('http://Alice:password@server:8080', url.full)
+
+    def test_escape_userinfo(self):
+        '''user and passwd should be escape'''
+        url = SafeURL('http://server', 'Alice', 'a;/?:@&=+$,b')
+
+        self.assertEqual('http://Alice:a%3B%2F%3F%3A%40%26%3D%2B%24%2Cb@server',
+                         url.full)
+
+    def test_join_a_file(self):
+        '''join a file'''
+        self.assertEqual('http://server/path/a/file.txt',
+                         SafeURL('http://server/path').pathjoin('a/file.txt'))
+
+    def test_join_with_tailing_slash(self):
+        '''join a file to url with tailing slash'''
+        self.assertEqual('http://server/path/a/file.txt',
+                         SafeURL('http://server/path/').pathjoin('a/file.txt'))
+
+    def test_join_a_dir(self):
+        '''join a dir'''
+        self.assertEqual('http://server/path/a/dir',
+                         SafeURL('http://server/path').pathjoin('a/dir'))
+
+    def test_reduce_doubel_dot(self):
+        '''reduce .. and get a path(alwasy with tailing slash)'''
+        url = SafeURL('http://server/a/b/c')
+
+        self.assertEqual('http://server/a/', url.pathjoin('../../'))
+        self.assertEqual('http://server/a/', url.pathjoin('../..'))
+
+    def test_local_path(self):
+        '''local path should not change'''
+        url = SafeURL('/local/path')
+
+        self.assertEqual('/local/path', url)
+        self.assertEqual(url, url.full)
+
+    def test_local_path_need_not_auth(self):
+        '''local path should ignore user and password'''
+        url = SafeURL('/local/path', 'test', 'password')
+
+        self.assertEqual('/local/path', url)
+        self.assertEqual(url, url.full)
diff --git a/tests/testdata/ConsoleKit-0.4.5.zip b/tests/testdata/ConsoleKit-0.4.5.zip
new file mode 100644 (file)
index 0000000..4e60dfc
Binary files /dev/null and b/tests/testdata/ConsoleKit-0.4.5.zip differ
diff --git a/tests/testdata/ail-0.2.29-2.3.src.rpm b/tests/testdata/ail-0.2.29-2.3.src.rpm
new file mode 100644 (file)
index 0000000..c6e9b72
Binary files /dev/null and b/tests/testdata/ail-0.2.29-2.3.src.rpm differ
diff --git a/tests/testdata/ail-0.2.29-2.5.src.rpm b/tests/testdata/ail-0.2.29-2.5.src.rpm
new file mode 100644 (file)
index 0000000..d7a25f8
Binary files /dev/null and b/tests/testdata/ail-0.2.29-2.5.src.rpm differ
diff --git a/tests/testdata/app-core-1.2-19.3.src.rpm b/tests/testdata/app-core-1.2-19.3.src.rpm
new file mode 100644 (file)
index 0000000..0510d6f
Binary files /dev/null and b/tests/testdata/app-core-1.2-19.3.src.rpm differ
diff --git a/tests/testdata/bad.spec b/tests/testdata/bad.spec
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/testdata/bad.src.rpm b/tests/testdata/bad.src.rpm
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/testdata/bison-1.27.tar.gz b/tests/testdata/bison-1.27.tar.gz
new file mode 100644 (file)
index 0000000..9c2fec6
Binary files /dev/null and b/tests/testdata/bison-1.27.tar.gz differ
diff --git a/tests/testdata/bluez_unpacked/Makefile b/tests/testdata/bluez_unpacked/Makefile
new file mode 100644 (file)
index 0000000..9b279ca
--- /dev/null
@@ -0,0 +1,6 @@
+PKG_NAME := bluez
+SPECFILE = $(addsuffix .spec, $(PKG_NAME))
+YAMLFILE = $(addsuffix .yaml, $(PKG_NAME))
+
+include /usr/share/packaging-tools/Makefile.common
+
diff --git a/tests/testdata/bluez_unpacked/bluetooth.init b/tests/testdata/bluez_unpacked/bluetooth.init
new file mode 100644 (file)
index 0000000..ed7845a
--- /dev/null
@@ -0,0 +1,67 @@
+#!/bin/sh
+#
+# chkconfig: 345 50 83
+# description: Bluetooth services for service discovery, authentication, \
+#             Human Interface Devices, etc.
+#
+### BEGIN INIT INFO
+# Required-Start: $syslog messagebus
+# Short-Description: Bluetooth services
+# Description: Bluetooth services for service discovery, authentication, 
+#  Human Interface Devices, etc.
+### END INIT INFO
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+[ -e /etc/sysconfig/bluetooth ] && . /etc/sysconfig/bluetooth
+
+start()
+{
+       echo -n $"Starting Bluetooth services:"
+       daemon /usr/sbin/bluetoothd
+       RETVAL=$?
+       [ $RETVAL = 0 ] && touch /var/lock/subsys/bluetoothd
+       [ "$HID2HCI_ENABLE" = "true" ] && hid2hci --tohci > /dev/null 2>&1 || :
+       touch /var/lock/subsys/bluetooth
+       echo ""
+       return $RETVAL
+}
+
+stop()
+{
+       echo -n "Stopping Bluetooth services:"
+       [ "$HID2HCI_UNDO" = "true" ] && hid2hci --tohid > /dev/null 2>&1 || :
+       killproc bluetoothd
+       RETVAL=$?
+       rm -f /var/lock/subsys/bluetooth
+       rm -f /var/lock/subsys/bluetoothd
+       echo ""
+       return $RETVAL
+}
+
+case "$1" in
+  start)
+       start
+       ;;
+  stop)
+       stop
+       ;;
+  force-reload|restart|reload)
+        stop
+        start
+        ;;
+  try-restart|condrestart)
+        [ -e /var/lock/subsys/bluetooth ] && (stop; start)
+        ;;
+  status)
+        status bluetoothd
+       RETVAL=$?
+        ;;
+  *)
+        echo $"Usage: $0 {start|stop|status|restart|reload|condrestart}"
+        exit 3
+       ;;
+esac
+
+exit $RETVAL
diff --git a/tests/testdata/bluez_unpacked/bluez-4.87.tar.gz b/tests/testdata/bluez_unpacked/bluez-4.87.tar.gz
new file mode 100644 (file)
index 0000000..59667ed
Binary files /dev/null and b/tests/testdata/bluez_unpacked/bluez-4.87.tar.gz differ
diff --git a/tests/testdata/bluez_unpacked/bluez-fsync.patch b/tests/testdata/bluez_unpacked/bluez-fsync.patch
new file mode 100644 (file)
index 0000000..10cd10a
--- /dev/null
@@ -0,0 +1,11 @@
+--- bluez-4.28/src/textfile.c~ 2009-02-11 03:01:06.000000000 -0800
++++ bluez-4.28/src/textfile.c  2009-02-11 03:01:06.000000000 -0800
+@@ -271,7 +271,7 @@
+       flock(fd, LOCK_UN);
+ close:
+-      fdatasync(fd);
++//    fdatasync(fd);
+       close(fd);
+       errno = err;
diff --git a/tests/testdata/bluez_unpacked/bluez.changes b/tests/testdata/bluez_unpacked/bluez.changes
new file mode 100644 (file)
index 0000000..b8a1cf8
--- /dev/null
@@ -0,0 +1,157 @@
+* Thu Feb 10 2011 Zheng wu <wu.zheng@intel.com> - 4.87
+- upgrade to 4.87 for BMC #13393
+- ver 4.87:
+       Fix issue with initialization when adapter is already up.
+       Fix issue with attribute server MTU and incoming connections.
+       Fix issue with duplicate characteristics after discovery.
+
+* Fri Jan 21 2011 Zheng wu <wu.zheng@intel.com> - 4.86
+- upgrade to 4.86 for BMC #12691
+- ver 4.86:
+       Revert wrong fix for SDP PDU size error response.
+       Fix various memory leaks in A2DP and AVDTP support.
+       Add Routing property to MediaTransport interface
+       Add proper tracking mechanism to NREC status.
+       Add READ_BLOB_REQUEST support to attribute server.
+
+* Thu Jan 13 2011 Martin Xu <martin.xu@intel.com> - 4.85
+- upgrade to 4.85 
+- to partly support Bluetooth LE feature, FEA #7110
+
+* Thu Jan  6 2011 Zhang Qiang<qiang.z.zhang@intel.com> 4.84
+- Upgrade to 4.84
+
+* Mon Oct 25 2010 Zhu Yanhai <yanhai.zhu@linux.intel.com> 4.76
+- Add disable-hal-plugin.patch to fix BMC#7676.
+
+* Mon Oct 25 2010 Zhu Yanhai <yanhai.zhu@linux.intel.com> 4.76
+- Add Fix-crash-in-Manager.GetProperties.patch to fix BMC#7772.
+
+* Mon Oct 18 2010 Zhu Yanhai <yanhai.zhu@linux.intel.com> 4.76
+- Upgrade to 4.76
+
+* Thu Sep 30 2010 Zhu Yanhai <yanhai.zhu@linux.intel.com> 4.70
+- Add powered.patch to make sure the initial power status aligned
+  with connman's requirement.
+
+* Fri Aug 27 2010 Zhu Yanhai <yanhai.zhu@linux.intel.com> 4.70
+- Upgrade to 4.70
+
+* Mon Jul 26 2010 Zhu Yanhai <yanhai.zhu@linux.intel.com> 4.69
+- Add more binary test programs into bluez-test sub-package.
+
+* Mon Jul 19 2010 Zhu Yanhai <yanhai.zhu@linux.intel.com> 4.69
+- Upgrade to 4.69
+
+* Thu Jul 15 2010 Anas Nashif <anas.nashif@intel.com> - 4.66
+- Install udev rules into /lib/udev (bmc #3424)
+
+* Tue Jul 13 2010 Zhu Yanhai <yanhai.zhu@linux.intel.com> 4.66
+- Add a sub-package for test scripts.
+- Corrected bluez.yaml to avoid spectacle's warnings.
+
+* Wed Jun 30 2010 Zhu Yanhai <yanhai.zhu@linux.intel.com> 4.66
+- Upgrade to 4.66
+- Remove unnecessary patch correct-ref.patch
+- Switch to build with Spectacle
+
+* fri jun 4 2010 zhu yanhai <yanhai.zhu@linux.intel.com> 4.65
+- add correct-ref.patch to fix bmc#1882
+
+* Thu Jun 3 2010 Zhu Yanhai <yanhai.zhu@linux.intel.com> 4.65
+- Upgrade to 4.65
+
+* Tue Apr 27 2010 Zhu Yanhai <yanhai.zhu@linux.intel.com> 4.63
+- Enable HFP without oFono binding in Trunk. Because IVI and Netbooks don't have a
+  physical modem, we just build BlueZ with the default dummy telephony driver.
+  (BMC#400). This will make MeeGo BlueZ be able to play HFP HS and AG role.
+
+* Mon Apr 12 2010 Zhu Yanhai <yanhai.zhu@linux.intel.com> 4.63
+- Upgrade to 4.63. As the HSP part is under changes in upstream, this upgrade
+  will potentially improve HSP performance (BMC#65, BMC#400, BMC#402)
+- Refresh no-crash-if-no-modem.path: use the hotifx from upstream to
+  replace my home made one. (BMO#8991)
+
+* Tue Mar 9 2010 Zhu Yanhai <yanhai.zhu@linux.intel.com> 4.62
+- Upgrade to 4.62, which also fix bluez-hcidump build failure.
+
+* Sat Feb 27 2010 Anas Nashif <anas.nashif@intel.com> - 4.61
+- Spec cleanup
+
+* Thu Feb 25 2010 Zhu Yanhai <yanhai.zhu@linux.intel.com> 4.61
+- Upgrade to 4.61
+
+* Tue Feb 2 2010 Zhu Yanhai <yanhai.zhu@linux.intel.com> 4.60
+- Upgrade to 4.60
+
+* Tue Jan 12 2010 Zhu Yanhai <yanhai.zhu@linux.intel.com> 4.58
+- add no-crash-if-no-modem.patch to fix MB#8991. 
+
+* Fri Dec 4 2009 Martin Xu  <martin.xu@intel.com> 4.58
+- upgrade to 4.58
+
+* Fri Dec 4 2009 Martin Xu  <martin.xu@intel.com> 4.56
+- add set_RememberPowered_as_false.patch to partly fix bug #6835
+
+* Tue Oct 28 2009 Martin Xu  <martin.xu@intel.com> 4.56
+- add disable_HFP_at_audio_conf.patch to fix bug# 7236
+
+* Tue Oct 13 2009 Martin Xu  <martin.xu@intel.com> 4.56
+- Upgrade to 4.56
+- update bluez-fsync.patch
+
+* Thu Sep 17 2009 Yi Yang <yi.y.yang@intel.com> 4.50
+- Remove a duplicate but wrong udev rule for dell mice (MB#5316)
+
+* Fri Aug 27 2009 Martin Xu  <martin.xu@intel.com> 4.50
+- Upgrade to 4.50
+- Add --with-telephony=ofono to enable HFP telephony plugins See Bug #5486
+- Add ofono as runtime requirements
+
+* Fri Aug 7 2009 Martin Xu  <martin.xu@intel.com> 4.47
+- Upgrade to 4.47
+- Remove HFP patch, the patch has been included in 4.47
+
+* Wed July 1 2009 Todd Brandt <todd.e.brandt@intel.com> 4.40
+- Added Forrest Zhao's HFP support patch. Fixes a crash when using org.bluez.HeadsetGateway
+
+* Thu June 4 2009 Martin Xu  <martin.xu@intel.com> 4.40
+- Upgrade to 4.40
+- Remove fix-alsa-bluez-plugin-poll-revents-err.patch, the fix has been done in alsa-lib-1.0.20 
+
+* Mon May 25 2009 Anas Nashif <anas.nashif@intel.com> 4.38
+- Fixed ChangeLog
+
+* Fri May 8 2009 Martin Xu  <martin.xu@intel.com> 4.38
+- Upgrade to 4.38
+
+ Tue Apr 28 2009  <martin.xu@intel.com> 4.36
+- Upgrade to 4.36
+
+* Fri Apr 3 2009  <martin.xu@intel.com> 4.30
+- add patch fix-alsa-bluez-plugin-poll-revents-err.patch to fix a2dp error
+
+ Fri Feb 13 2009 Anas Nashif <anas.nashif@intel.com> 4.30
+- Update to 4.30
+
+* Tue Feb 10 2009 Arjan van de Ven <arjan@linux.intel.com> 4.28
+- disable f(data)sync calls in bluetoothd
+
+* Mon Feb 9 2009 Arjan van de Ven <arjan@linux.intel.com> 4.28
+- update to 4.28
+- don't start the daemon from the initscript
+
+* Thu Dec 11 2008 Anas Nashif <anas.nashif@intel.com> 4.22
+- fastinit replaces initscripts
+
+* Thu Dec 11 2008 - Martin Xu <martin.xu@intel.com>
+- Upgrade to bluez-4.22
+
+* Tue Dec 09 2008 Anas Nashif <anas.nashif@intel.com> 4.18
+- Change BR for gstreamer plugins
+
+* Fri Nov 25 2008 - Martin Xu <martin.xu@intel.com>
+- Remove "Provides bluez-utils-*"
+
+* Fri Nov 11 2008 - Martin Xu <martin.xu@intel.com>
+- initialized bluez-4.18 package
diff --git a/tests/testdata/bluez_unpacked/bluez.spec b/tests/testdata/bluez_unpacked/bluez.spec
new file mode 100644 (file)
index 0000000..e3545e6
--- /dev/null
@@ -0,0 +1,290 @@
+# 
+# Do NOT Edit the Auto-generated Part!
+# Generated by: spectacle version 0.21
+# 
+# >> macros
+# << macros
+
+Name:       bluez
+Summary:    Bluetooth utilities
+Version:    4.87
+Release:    1
+Group:      Applications/System
+License:    GPLv2+
+URL:        http://www.bluez.org/
+Source0:    http://www.kernel.org/pub/linux/bluetooth/%{name}-%{version}.tar.gz
+Source1:    bluetooth.init
+Source100:  bluez.yaml
+Patch0:     bluez-fsync.patch
+Patch1:     remove-duplicate-wrong-udev-rule-for-dell-mice.patch
+Patch2:     enable_HFP.patch
+Patch3:     powered.patch
+Patch4:     install-test-scripts.patch
+Patch5:     install-more-binary-test.patch
+Patch6:     disable-hal-plugin.patch
+Requires:   bluez-libs = %{version}
+Requires:   dbus >= 0.60
+Requires:   hwdata >= 0.215
+Requires:   ofono >= 0.2
+Requires(post): /sbin/service
+Requires(post): /sbin/chkconfig
+Requires(postun): /sbin/service
+Requires(postun): /sbin/chkconfig
+BuildRequires:  pkgconfig(dbus-1)
+BuildRequires:  pkgconfig(libusb)
+BuildRequires:  pkgconfig(alsa)
+BuildRequires:  pkgconfig(udev)
+BuildRequires:  pkgconfig(sndfile)
+BuildRequires:  pkgconfig(glib-2.0)
+BuildRequires:  pkgconfig(gstreamer-plugins-base-0.10)
+BuildRequires:  pkgconfig(gstreamer-0.10)
+BuildRequires:  flex
+
+
+%description
+Utilities for use in Bluetooth applications:
+       --ciptool
+       --dfutool
+       --hcitool
+       --l2ping
+       --rfcomm
+       --sdptool
+       --hciattach
+       --hciconfig
+       --hid2hci
+
+The BLUETOOTH trademarks are owned by Bluetooth SIG, Inc., U.S.A.
+
+
+
+%package libs
+Summary:    Libraries for use in Bluetooth applications
+Group:      System/Libraries
+Requires:   %{name} = %{version}-%{release}
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description libs
+Libraries for use in Bluetooth applications.
+
+%package libs-devel
+Summary:    Development libraries for Bluetooth applications
+Group:      Development/Libraries
+Requires:   %{name} = %{version}-%{release}
+Requires:   bluez-libs = %{version}
+
+%description libs-devel
+bluez-libs-devel contains development libraries and headers for
+use in Bluetooth applications.
+
+
+%package cups
+Summary:    CUPS printer backend for Bluetooth printers
+Group:      System/Daemons
+Requires:   %{name} = %{version}-%{release}
+Requires:   bluez-libs = %{version}
+Requires:   cups
+
+%description cups
+This package contains the CUPS backend
+
+%package alsa
+Summary:    ALSA support for Bluetooth audio devices
+Group:      System/Daemons
+Requires:   %{name} = %{version}-%{release}
+Requires:   bluez-libs = %{version}
+
+%description alsa
+This package contains ALSA support for Bluetooth audio devices
+
+%package gstreamer
+Summary:    GStreamer support for SBC audio format
+Group:      System/Daemons
+Requires:   %{name} = %{version}-%{release}
+Requires:   bluez-libs = %{version}
+
+%description gstreamer
+This package contains gstreamer plugins for the Bluetooth SBC audio format
+
+%package test
+Summary:    Test Programs for BlueZ
+Group:      Development/Tools
+Requires:   %{name} = %{version}-%{release}
+Requires:   bluez-libs = %{version}
+Requires:   dbus-python
+Requires:   pygobject2
+
+%description test
+Scripts for testing BlueZ and its functionality
+
+
+%prep
+%setup -q -n %{name}-%{version}
+
+# bluez-fsync.patch
+%patch0 -p1
+# remove-duplicate-wrong-udev-rule-for-dell-mice.patch
+%patch1 -p1
+# enable_HFP.patch
+%patch2 -p1
+# powered.patch
+%patch3 -p1
+# install-test-scripts.patch
+%patch4 -p1
+# install-more-binary-test.patch
+%patch5 -p1
+# disable-hal-plugin.patch
+%patch6 -p1
+# >> setup
+# << setup
+
+%build
+# >> build pre
+# << build pre
+
+%reconfigure --disable-static \
+    --enable-cups \
+    --enable-hid2hci \
+    --enable-dfutool \
+    --enable-bccmd \
+    --enable-hidd \
+    --enable-pand \
+    --enable-dund \
+    --enable-gstreamer \
+    --enable-alsa \
+    --enable-usb \
+    --enable-tools \
+    --enable-test \
+    --with-telephony=dummy
+
+make %{?jobs:-j%jobs}
+
+# >> build post
+# << build post
+%install
+rm -rf %{buildroot}
+# >> install pre
+# << install pre
+%make_install
+
+# >> install post
+
+install -D -m0755 %SOURCE1 $RPM_BUILD_ROOT%{_sysconfdir}/rc.d/init.d/bluetooth
+
+# Remove the cups backend from libdir, and install it in /usr/lib whatever the install
+rm -rf ${RPM_BUILD_ROOT}%{_libdir}/cups
+install -D -m0755 cups/bluetooth ${RPM_BUILD_ROOT}/usr/lib/cups/backend/bluetooth
+
+install -d -m0755 $RPM_BUILD_ROOT/%{_localstatedir}/lib/bluetooth
+
+# << install post
+
+
+
+
+
+
+
+%post libs -p /sbin/ldconfig
+
+%postun libs -p /sbin/ldconfig
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%files
+%defattr(-,root,root,-)
+# >> files
+%defattr(-, root, root)
+%{_bindir}/ciptool
+%{_bindir}/dfutool
+%{_bindir}/dund
+%{_bindir}/hcitool
+%{_bindir}/hidd
+%{_bindir}/l2ping
+%{_bindir}/pand
+%{_bindir}/rfcomm
+%{_bindir}/sdptool
+%{_sbindir}/*
+%doc %{_mandir}/man1/*
+%doc %{_mandir}/man8/*
+%config(noreplace) %{_sysconfdir}/bluetooth/*
+%config %{_sysconfdir}/dbus-1/system.d/bluetooth.conf
+%exclude /etc/rc.d/init.d/*
+%{_localstatedir}/lib/bluetooth
+/lib/udev/*
+# << files
+
+
+%files libs
+%defattr(-,root,root,-)
+# >> files libs
+%defattr(-, root, root)
+%{_libdir}/libbluetooth.so.*
+%doc AUTHORS COPYING INSTALL README
+# << files libs
+
+%files libs-devel
+%defattr(-,root,root,-)
+# >> files libs-devel
+%defattr(-, root, root)
+%{_libdir}/libbluetooth.so
+%dir %{_includedir}/bluetooth
+%{_includedir}/bluetooth/*
+%{_libdir}/pkgconfig/bluez.pc
+# << files libs-devel
+
+%files cups
+%defattr(-,root,root,-)
+# >> files cups
+%defattr(-, root, root)
+/usr/lib/cups/backend/bluetooth
+# << files cups
+
+%files alsa
+%defattr(-,root,root,-)
+# >> files alsa
+%defattr(-, root, root)
+%{_libdir}/alsa-lib/*.so
+%{_datadir}/alsa/bluetooth.conf
+# << files alsa
+
+%files gstreamer
+%defattr(-,root,root,-)
+# >> files gstreamer
+%defattr(-, root, root)
+%{_libdir}/gstreamer-*/*.so
+# << files gstreamer
+
+%files test
+%defattr(-,root,root,-)
+# >> files test
+%{_libdir}/%{name}/test/*
+%{_bindir}/hstest
+%{_bindir}/gaptest
+%{_bindir}/sdptest
+%{_bindir}/l2test
+%{_bindir}/btiotest
+%{_bindir}/avtest
+%{_bindir}/bdaddr
+%{_bindir}/scotest
+%{_bindir}/lmptest
+%{_bindir}/attest
+%{_bindir}/agent
+%{_bindir}/test-textfile
+%{_bindir}/rctest
+%{_bindir}/ipctest
+# << files test
+
diff --git a/tests/testdata/bluez_unpacked/bluez.yaml b/tests/testdata/bluez_unpacked/bluez.yaml
new file mode 100644 (file)
index 0000000..c41a277
--- /dev/null
@@ -0,0 +1,111 @@
+Name: bluez
+Summary: Bluetooth utilities
+Version: 4.87
+Release: 1
+Group: Applications/System
+License: GPLv2+
+URL: http://www.bluez.org/
+Sources:
+    - http://www.kernel.org/pub/linux/bluetooth/%{name}-%{version}.tar.gz
+    - bluetooth.init
+Patches:
+    - bluez-fsync.patch
+    - remove-duplicate-wrong-udev-rule-for-dell-mice.patch
+    - enable_HFP.patch
+    - powered.patch
+    - install-test-scripts.patch
+    - install-more-binary-test.patch
+    - disable-hal-plugin.patch
+Description: |
+    Utilities for use in Bluetooth applications:
+       --ciptool
+       --dfutool
+       --hcitool
+       --l2ping
+       --rfcomm
+       --sdptool
+       --hciattach
+       --hciconfig
+       --hid2hci
+    
+    The BLUETOOTH trademarks are owned by Bluetooth SIG, Inc., U.S.A.
+
+Requires:
+    - bluez-libs = %{version}
+    - dbus >= 0.60
+    - hwdata >= 0.215
+    - ofono >= 0.2
+
+PkgConfigBR:
+    - dbus-1
+    - libusb
+    - alsa
+    - udev
+    - sndfile
+    - glib-2.0
+    - gstreamer-plugins-base-0.10
+    - gstreamer-0.10
+
+PkgBR:
+    - flex
+Configure: reconfigure
+ConfigOptions:
+    - --enable-cups
+    - --enable-hid2hci
+    - --enable-dfutool
+    - --enable-bccmd
+    - --enable-hidd
+    - --enable-pand
+    - --enable-dund
+    - --enable-gstreamer
+    - --enable-alsa
+    - --enable-usb
+    - --enable-tools
+    - --enable-test
+    - --with-telephony=dummy
+Builder: make
+SubPackages:
+    - Name: libs
+      Summary: Libraries for use in Bluetooth applications
+      Group: System/Libraries
+      Description: Libraries for use in Bluetooth applications.
+
+    - Name: libs-devel
+      Summary: Development libraries for Bluetooth applications
+      Group: Development/Libraries
+      Description: |
+          bluez-libs-devel contains development libraries and headers for
+          use in Bluetooth applications.
+      Requires:
+          - bluez-libs = %{version}
+
+    - Name: cups
+      Summary: CUPS printer backend for Bluetooth printers
+      Group: System/Daemons
+      Description: This package contains the CUPS backend
+      Requires:
+          - bluez-libs = %{version}
+          - cups
+
+    - Name: alsa
+      Summary: ALSA support for Bluetooth audio devices
+      Group: System/Daemons
+      Description: This package contains ALSA support for Bluetooth audio devices
+      Requires:
+          - bluez-libs = %{version}
+
+    - Name: gstreamer
+      Summary: GStreamer support for SBC audio format
+      Group: System/Daemons
+      Description: This package contains gstreamer plugins for the Bluetooth SBC audio format
+      Requires:
+          - bluez-libs = %{version}
+
+    - Name: test
+      Summary: Test Programs for BlueZ
+      Group: Development/Tools
+      Description: Scripts for testing BlueZ and its functionality
+      Requires:
+          - bluez-libs = %{version}
+          - dbus-python
+          - pygobject2
diff --git a/tests/testdata/bluez_unpacked/disable-hal-plugin.patch b/tests/testdata/bluez_unpacked/disable-hal-plugin.patch
new file mode 100644 (file)
index 0000000..28e783c
--- /dev/null
@@ -0,0 +1,11 @@
+diff -Nur old/src/main.conf new/src/main.conf
+--- old/src/main.conf  2010-10-25 16:23:53.000000000 +0800
++++ new/src/main.conf  2010-10-25 16:26:03.000000000 +0800
+@@ -59,3 +59,7 @@
+ # Enable the GATT Attribute Server. Default is false, because it is only
+ # useful for testing.
+ AttributeServer = false
++
++
++# Disable the HAL plugin here since MeeGo has removed hald.
++DisablePlugins=hal
diff --git a/tests/testdata/bluez_unpacked/enable_HFP.patch b/tests/testdata/bluez_unpacked/enable_HFP.patch
new file mode 100644 (file)
index 0000000..78a3537
--- /dev/null
@@ -0,0 +1,24 @@
+diff -Nur old/audio/audio.conf new/audio/audio.conf
+--- old/audio/audio.conf       2009-10-31 15:18:09.000000000 +0800
++++ new/audio/audio.conf       2010-04-26 12:37:02.000000000 +0800
+@@ -3,7 +3,7 @@
+ # This section contains options which are not specific to any
+ # particular interface
+ [General]
+-
++Enable=Gateway
+ # Switch to master role for incoming connections (defaults to true)
+ #Master=true
+diff -Nur old/Makefile.am new/Makefile.am
+--- old/Makefile.am    2010-03-26 03:27:55.000000000 +0800
++++ new/Makefile.am    2010-04-26 12:36:43.000000000 +0800
+@@ -211,7 +211,7 @@
+ man_MANS = src/bluetoothd.8
+ if CONFIGFILES
+-conf_DATA += src/main.conf
++conf_DATA += src/main.conf audio/audio.conf
+ endif
+ EXTRA_DIST += src/genbuiltin src/bluetooth.conf \
diff --git a/tests/testdata/bluez_unpacked/install-more-binary-test.patch b/tests/testdata/bluez_unpacked/install-more-binary-test.patch
new file mode 100644 (file)
index 0000000..0d65c2e
--- /dev/null
@@ -0,0 +1,12 @@
+diff -Nur old/Makefile.tools new/Makefile.tools
+--- old/Makefile.tools 2010-05-23 20:47:19.000000000 +0800
++++ new/Makefile.tools 2010-07-26 17:50:02.000000000 +0800
+@@ -135,7 +135,7 @@
+ bin_PROGRAMS += test/l2test test/rctest
+-noinst_PROGRAMS += test/gaptest test/sdptest test/scotest \
++bin_PROGRAMS += test/gaptest test/sdptest test/scotest \
+                       test/attest test/hstest test/avtest test/ipctest \
+                                       test/lmptest test/bdaddr test/agent \
+                                       test/btiotest test/test-textfile
diff --git a/tests/testdata/bluez_unpacked/install-test-scripts.patch b/tests/testdata/bluez_unpacked/install-test-scripts.patch
new file mode 100644 (file)
index 0000000..b77ee14
--- /dev/null
@@ -0,0 +1,35 @@
+diff -Nur old/Makefile.am new/Makefile.am
+--- old/Makefile.am    2010-05-23 20:47:19.000000000 +0800
++++ new/Makefile.am    2010-07-13 15:22:47.000000000 +0800
+@@ -304,6 +304,31 @@
+ dist_udev_SCRIPTS = scripts/bluetooth_serial
+ endif
++
++test_scripts = test/apitest \
++      test/hsplay \
++      test/hsmicro \
++      test/list-devices \
++      test/monitor-bluetooth \
++      test/simple-agent \
++      test/simple-service \
++      test/test-adapter \
++      test/test-audio \
++      test/test-device \
++      test/test-discovery \
++      test/test-input \
++      test/test-manager \
++      test/test-network \
++      test/test-serial \
++      test/test-service \
++      test/test-telephony
++
++
++if TEST
++testdir = ${pkglibdir}/test
++test_SCRIPTS = ${test_scripts}
++endif
++
+ EXTRA_DIST += doc/manager-api.txt \
+               doc/adapter-api.txt doc/device-api.txt \
+               doc/service-api.txt doc/agent-api.txt \
diff --git a/tests/testdata/bluez_unpacked/powered.patch b/tests/testdata/bluez_unpacked/powered.patch
new file mode 100644 (file)
index 0000000..cc48df9
--- /dev/null
@@ -0,0 +1,16 @@
+diff -Nur old/src/main.conf new/src/main.conf
+--- old/src/main.conf  2010-08-25 13:10:02.000000000 +0800
++++ new/src/main.conf  2010-09-26 17:28:39.000000000 +0800
+@@ -32,10 +32,10 @@
+ # What value should be assumed for the adapter Powered property when
+ # SetProperty(Powered, ...) hasn't been called yet. Defaults to true
+-InitiallyPowered = true
++InitiallyPowered = false
+ # Remember the previously stored Powered state when initializing adapters
+-RememberPowered = true
++RememberPowered = false
+ # Use vendor, product and version information for DID profile support.
+ # The values are separated by ":" and VID, PID and version.
diff --git a/tests/testdata/bluez_unpacked/remove-duplicate-wrong-udev-rule-for-dell-mice.patch b/tests/testdata/bluez_unpacked/remove-duplicate-wrong-udev-rule-for-dell-mice.patch
new file mode 100644 (file)
index 0000000..2f76a4f
--- /dev/null
@@ -0,0 +1,13 @@
+diff --git a/scripts/bluetooth-hid2hci.rules b/scripts/bluetooth-hid2hci.rules
+index 1b231d1..c834957 100644
+--- a/scripts/bluetooth-hid2hci.rules
++++ b/scripts/bluetooth-hid2hci.rules
+@@ -8,7 +8,7 @@
+ #   413c:8154
+ #   413c:8158
+ #   413c:8162
+-ACTION=="add", ENV{ID_VENDOR}=="413c", ENV{ID_CLASS}=="mouse", ATTRS{bmAttributes}=="e0", KERNEL=="mouse*", RUN+="/usr/sbin/hid2hci --method dell -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
++# udev 144 or later has covered these Dell mice, so unnecessary to have a duplicate but wrong rule.
+ # Logitech devices
+ ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c703" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
diff --git a/tests/testdata/ini/bad_passwdx.ini b/tests/testdata/ini/bad_passwdx.ini
new file mode 100644 (file)
index 0000000..b16c961
--- /dev/null
@@ -0,0 +1,3 @@
+[remotebuild]
+build_server = https://api
+passwdx = secret
\ No newline at end of file
diff --git a/tests/testdata/ini/bug387_inherit_only_passwdx.ini b/tests/testdata/ini/bug387_inherit_only_passwdx.ini
new file mode 100644 (file)
index 0000000..fbfe399
--- /dev/null
@@ -0,0 +1,16 @@
+[general]
+profile = profile.test
+
+[profile.test]
+repos = repo.test
+obs = obs.test
+
+passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
+
+[repo.test]
+url = https://repo
+user = tester
+
+[obs.test]
+url = https://obs
+user = tester
\ No newline at end of file
diff --git a/tests/testdata/ini/bug387_inherit_only_user.ini b/tests/testdata/ini/bug387_inherit_only_user.ini
new file mode 100644 (file)
index 0000000..e5bb6d8
--- /dev/null
@@ -0,0 +1,16 @@
+[general]
+profile = profile.test
+
+[profile.test]
+repos = repo.test
+obs = obs.test
+
+user = tester
+
+[repo.test]
+url = https://repo
+passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
+
+[obs.test]
+url = https://obs
+passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
diff --git a/tests/testdata/ini/bug387_inline_auth_has_the_highest_priority.ini b/tests/testdata/ini/bug387_inline_auth_has_the_highest_priority.ini
new file mode 100644 (file)
index 0000000..478a04a
--- /dev/null
@@ -0,0 +1,10 @@
+[general]
+profile = profile.test
+
+[profile.test]
+obs = obs.test
+
+[obs.test]
+url = https://this:inline-pwd@obs
+user = tester
+passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
diff --git a/tests/testdata/ini/bug387_only_password_no_user.ini b/tests/testdata/ini/bug387_only_password_no_user.ini
new file mode 100644 (file)
index 0000000..a8d63c8
--- /dev/null
@@ -0,0 +1,13 @@
+[general]
+profile = profile.test
+
+[profile.test]
+repos = repo.test
+obs = obs.test
+passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
+
+[repo.test]
+url = https://repo
+
+[obs.test]
+url = https://obs
diff --git a/tests/testdata/ini/empty_passwdx.ini b/tests/testdata/ini/empty_passwdx.ini
new file mode 100644 (file)
index 0000000..cc63375
--- /dev/null
@@ -0,0 +1,3 @@
+[remotebuild]
+build_server = https://api
+passwdx =
\ No newline at end of file
diff --git a/tests/testdata/ini/empty_profile.ini b/tests/testdata/ini/empty_profile.ini
new file mode 100644 (file)
index 0000000..e9f1ab3
--- /dev/null
@@ -0,0 +1,4 @@
+[general]
+profile = profile.test
+
+[profile.test]
\ No newline at end of file
diff --git a/tests/testdata/ini/home1.ini b/tests/testdata/ini/home1.ini
new file mode 100644 (file)
index 0000000..6a996f5
--- /dev/null
@@ -0,0 +1,7 @@
+[section]
+common_key = homev1
+home_only_key = homev2
+
+[profile.rsa]
+common = homev3
+home_only = homev4
diff --git a/tests/testdata/ini/interpolation.ini b/tests/testdata/ini/interpolation.ini
new file mode 100644 (file)
index 0000000..256f991
--- /dev/null
@@ -0,0 +1,3 @@
+[remote]
+base = abc
+target = %(base)s/def
\ No newline at end of file
diff --git a/tests/testdata/ini/invalid_continuation_line.ini b/tests/testdata/ini/invalid_continuation_line.ini
new file mode 100644 (file)
index 0000000..5bee728
--- /dev/null
@@ -0,0 +1,2 @@
+[general]
+ profile = test
\ No newline at end of file
diff --git a/tests/testdata/ini/no_such_profile_section_name.ini b/tests/testdata/ini/no_such_profile_section_name.ini
new file mode 100644 (file)
index 0000000..d1622ee
--- /dev/null
@@ -0,0 +1,2 @@
+[general]
+profile = profile.test
\ No newline at end of file
diff --git a/tests/testdata/ini/normal_passwdx.ini b/tests/testdata/ini/normal_passwdx.ini
new file mode 100644 (file)
index 0000000..1eeafe3
--- /dev/null
@@ -0,0 +1,3 @@
+[remotebuild]
+build_server = https://api
+passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
\ No newline at end of file
diff --git a/tests/testdata/ini/passwdx.ini b/tests/testdata/ini/passwdx.ini
new file mode 100644 (file)
index 0000000..1eeafe3
--- /dev/null
@@ -0,0 +1,3 @@
+[remotebuild]
+build_server = https://api
+passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
\ No newline at end of file
diff --git a/tests/testdata/ini/plain_passwd.ini b/tests/testdata/ini/plain_passwd.ini
new file mode 100644 (file)
index 0000000..8693a6c
--- /dev/null
@@ -0,0 +1,7 @@
+[remotebuild]
+build_server = https://api
+passwd = secret
+
+[build]
+repo1.url = https://repo1
+repo1.passwd = secret
diff --git a/tests/testdata/ini/plain_passwd2.ini b/tests/testdata/ini/plain_passwd2.ini
new file mode 100644 (file)
index 0000000..46db241
--- /dev/null
@@ -0,0 +1,9 @@
+[remotebuild]
+build_server = https://api
+user = test
+passwd = secret
+
+[build]
+repo1.url = https://repo1
+repo1.user = test
+repo1.passwd = secret
\ No newline at end of file
diff --git a/tests/testdata/ini/profile.ini b/tests/testdata/ini/profile.ini
new file mode 100644 (file)
index 0000000..a646dc5
--- /dev/null
@@ -0,0 +1,29 @@
+[general]
+profile = profile.tz
+
+[profile.tz]
+user = Alice
+#passwd = secret
+passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
+repos = repo.ia32_main, repo.ia32_non-oss, repo.ia32_base, repo.local
+obs = obs.tz
+
+[obs.tz]
+url = https://api.tz/path
+base_prj = base
+target_prj = target
+
+[repo.ia32_main]
+url = https://repo/ia32/main
+
+[repo.ia32_non-oss]
+url = https://repo/ia32/non-oss
+
+[repo.ia32_base]
+url = https://repo/ia32/base
+user = Bob
+#passwd = classified
+passwdx = QlpoOTFBWSZTWRwZil4AAACBgC8kCAAgADEMCCAPKGaQLT4u5IpwoSA4MxS8
+
+[repo.local]
+url = /local/path
\ No newline at end of file
diff --git a/tests/testdata/ini/profile_only_has_api.ini b/tests/testdata/ini/profile_only_has_api.ini
new file mode 100644 (file)
index 0000000..5d3f6c9
--- /dev/null
@@ -0,0 +1,14 @@
+[general]
+profile = profile.test
+
+[profile.test]
+user = Alice
+#passwd = secret
+passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
+obs = obs.test_api
+
+[obs.test_api]
+url = https://api.tz/path
+user = Bob
+#passwd = classified
+passwdx = QlpoOTFBWSZTWRwZil4AAACBgC8kCAAgADEMCCAPKGaQLT4u5IpwoSA4MxS8
diff --git a/tests/testdata/ini/project1.ini b/tests/testdata/ini/project1.ini
new file mode 100644 (file)
index 0000000..aec2410
--- /dev/null
@@ -0,0 +1,7 @@
+[section]
+common_key = projv1
+proj_only_key = projv2
+
+[profile.rsa]
+common = projv3
+proj_only = projv4
diff --git a/tests/testdata/ini/subcommand.ini b/tests/testdata/ini/subcommand.ini
new file mode 100644 (file)
index 0000000..ea0a9bb
--- /dev/null
@@ -0,0 +1,18 @@
+[remotebuild]
+build_server = https://api/build/server
+user = Alice
+#passwd = secret
+passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
+base_prj = Main
+target_prj = Target
+
+[build]
+repo1.url = https://repo1/path
+repo1.user = Alice
+repo1.passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
+
+repo2.url = https://repo2/path
+repo2.user = Alice
+repo2.passwdx = QlpoOTFBWSZTWYfNdxYAAAIBgAoAHAAgADDNAMNEA24u5IpwoSEPmu4s
+
+repo3.url = /local/path/repo
\ No newline at end of file
diff --git a/tests/testdata/ini/without_section_header.ini b/tests/testdata/ini/without_section_header.ini
new file mode 100644 (file)
index 0000000..dfb28b1
--- /dev/null
@@ -0,0 +1 @@
+key = value
\ No newline at end of file
diff --git a/tools/gbs b/tools/gbs
new file mode 100755 (executable)
index 0000000..9cfa7d6
--- /dev/null
+++ b/tools/gbs
@@ -0,0 +1,459 @@
+#!/usr/bin/env python
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""Gbs - commandline tool for Tizen developers. Main module."""
+
+import sys
+import os
+
+from argparse import ArgumentParser
+
+from gitbuildsys import __version__
+from gitbuildsys import msger, errors
+from gitbuildsys.parsing import subparser, GbsHelpFormatter, basename_type
+
+
+@subparser
+def import_parser(parser):
+    """import spec file/source rpm/tar ball to git repository
+    Examples:
+      $ gbs import /path/to/specfile.spec
+      $ gbs import /path/to/package-version.src.rpm
+      $ gbs import /path/to/tarball.tar.gz
+    """
+
+    parser.add_argument('path', type=os.path.abspath,
+                        help='path to spec, srcrpm or tarball')
+
+    parser.add_argument('--author-name', help='author name of git commit')
+    parser.add_argument('--author-email', help='author email of git commit')
+    parser.add_argument('--upstream_branch', default='upstream',
+                        help='specify upstream branch for new package version')
+    parser.add_argument('--merge', action='store_true',
+                         help='merge new upstream branch to master')
+    parser.add_argument('--packaging-dir',
+                        help='directory containing packaging files')
+    parser.add_argument('--no-pristine-tar', action='store_true',
+                         help='don\'t use pristine-tar to import source. '
+                        'pristine-tar only support import *tar.{gz,bz2,xz} '
+                        'sources, this option can be specified to import '
+                        'other format sources')
+
+    parser.set_defaults(alias="im")
+    return parser
+
+@subparser
+def export_parser(parser):
+    """export files and prepare for build
+    Examples:
+      $ gbs export --spec my.spec --commit d64065c
+      $ gbs export --source-rpm -o /tmp/
+      $ gbs export --include-all
+    """
+
+    parser.add_argument('gitdir', nargs='?', type=os.path.abspath,
+                        default=os.getcwd(),
+                        help='path to git repository')
+
+    parser.add_argument('-o', '--outdir', help='output directory')
+    parser.add_argument('--spec', type=basename_type,
+                        help='specify a spec file to use. It should be a file '
+                        'name that GBS will find it in packaging dir')
+    parser.add_argument('-c', '--commit', help='specify a commit ID to export')
+    parser.add_argument('--include-all', action='store_true',
+                        help='uncommitted changes and untracked files '
+                        'would be included while generating tar ball')
+    parser.add_argument('--source-rpm', action='store_true',
+                        help='generate source rpm')
+    parser.add_argument('--upstream-branch', help='upstream branch')
+    parser.add_argument('--upstream-tag',
+                        help="upstream tag format, '${upstreamversion}' is "
+                        'expanded to the version in the spec file. '
+                        "E.g. 'v${upstreamversion}'")
+    parser.add_argument('--squash-patches-until',
+                         help='when generating patches, squash patches up '
+                         'to given commit-ish into one monolithic diff file. '
+                         'Format is the commit-ish optionally followed by a '
+                         'colon and diff filename base.')
+    parser.add_argument('--packaging-dir',
+                        help='directory containing packaging files')
+
+    parser.set_defaults(alias="ex")
+    return parser
+
+@subparser
+def build_parser(parser):
+    """local build package
+    Examples:
+      $ mkdir tizen-packages
+      $ cp package1 package2 package3 ... tizen-packages/
+      $ gbs build -A ia32 tizen-packages # build all packages from tizen-packages
+      $ cd tizen-packages/
+      $ gbs build -A ia32 # build all packages under current dir
+      $ gbs build -A ia32 --overwrite --include-all
+      $ gbs build -A i586 --threads=2
+      $ gbs build -A i586 --threads=2 --exclude=dlog --exclude=eglibc
+      $ gbs build -A i586 --threads=4 --binary-list=/path/to/pkgs.list
+      $ cd package1/
+      $ gbs build -A i586 --incremental # only support build one package
+
+      # Use repos specified from command line
+      $ gbs build -R http://user:passwd@example.org -R ... --skip-conf-repos
+      # Use repos specified from command line and gbs.conf
+      $ gbs build -R http://user:passwd@example.org -R ...
+
+
+    """
+
+    parser.add_argument('gitdir', nargs='?', type=os.path.abspath,
+                        default=os.getcwd(),
+                        help='path to git repository')
+
+    parser.add_argument('-D', '--dist',
+                        help='specify distribution configuration file, '
+                        'which should be a full path')
+    parser.add_argument('-R', '--repository', dest='repositories',
+                        action="append", help='specify package repositories, '
+                        'only rpm-md format is supported')
+    parser.add_argument('-B', '--buildroot',
+                        help='specify build root to setup chroot environment. '
+                        'By default, ~/GBS-ROOT/ will be used, and if no '
+                        '-B option, but TIZEN_BUILD_ROOT env exists, then '
+                        '${TIZEN_BUILD_ROOT} will used as build root')
+    parser.add_argument('-A', '--arch', help='build target arch ')
+    parser.add_argument('-P', '--profile',
+                        help='profile to be used for building, can be given '
+                             'without the "profile." prefix')
+    parser.add_argument('-C', '--clean', action='store_true',
+                        help='delete old build root before initialization')
+    parser.add_argument('--clean-repos', action='store_true',
+                        help='clean up local repos created by gbs build '
+                        'before building packages')
+    parser.add_argument('--ccache', action="store_true",
+                        help='use ccache to speed up rebuilds')
+    parser.add_argument('--skip-conf-repos', action="store_true",
+                        help='skip repositories mentioned in config file')
+    parser.add_argument('-c', '--commit', help='specify a commit ID to build')
+    parser.add_argument('--spec', type=basename_type,
+                        help='specify a spec file to use. It should be a file '
+                        'name that GBS will find it in packaging dir')
+    parser.add_argument('--extra-packs',
+                        help='specify extra packages to install to build root '
+                        'multiple packages can be separated by comma')
+    parser.add_argument('--include-all', action='store_true',
+                        help='uncommitted changes and untracked files would be '
+                        'included while generating tar ball')
+    parser.add_argument('--upstream-branch', help='upstream branch')
+    parser.add_argument('--upstream-tag',
+                        help="upstream tag format, '${upstreamversion}' is "
+                       "expanded to the version in the spec file. "
+                        "E.g. 'v${upstreamversion}'")
+    parser.add_argument('--squash-patches-until',
+                        help='when generating patches, squash patches up '
+                        'to given commit-ish into one monolithic diff file. '
+                        'Format is the commit-ish optionally followed by a '
+                        'colon and diff filename base.')
+    parser.add_argument('--packaging-dir',
+                        help='directory containing packaging files')
+
+    # depanneur special options
+    parser.add_argument('--clean-once', action='store_true',
+                        help='clean the build environment only once when you '
+                        'start building multiple packages, after that use '
+                        'existing environment for all packages.')
+    parser.add_argument('--overwrite', action='store_true',
+                        help='overwrite existing binaries and build '
+                        'them anyway')
+    parser.add_argument('--incremental', action='store_true',
+                       help='build a package from the local git tree '
+                        'incremental. If the build fails, changes can be done '
+                        'directly to the source and build can continue from '
+                        'where it stopped')
+    parser.add_argument('--debug', action='store_true', help='debug output')
+    parser.add_argument('--binary-list',
+                        help='specify a binary list file. Packages listed in '
+                       'this file will be selected to be built. The format '
+                       'of binary-list file is one package for one line, '
+                       'and only binary RPM name is accepted')
+    parser.add_argument('--threads', type=int, default=1,
+                        help='number of threads to build package in parallel')
+    parser.add_argument('--exclude', action="append",
+                        help='specify a package to be excluded to be built')
+    parser.add_argument('--exclude-from-file',
+                        help='specify an exclude package list text file, the '
+                        'format is one package in one line, and only binary '
+                        'RPM package name is accepted. Packages listed in '
+                        'this file will be skipped to be built.')
+    parser.add_argument('--keepgoing', action='store_true',
+                        help='if a package build fails, do not abort and '
+                        'continue building other packages in the queue')
+    parser.add_argument('--no-configure', action='store_true',
+                        help='this option disables running configure scripts '
+                        'and auto generation of auto-tools to make incremental '
+                        'build possible. This requires the configure scripts '
+                        'in the spec to be referenced using the %%configure, '
+                        '%%reconfigure and %%autogen macros')
+    parser.add_argument('--noinit', action='store_true',
+                        help='start building directly')
+    parser.add_argument('--keep-packs', action='store_true',
+                        help='keep unused packages in build root. without '
+                        'this option, unused packages will be removed from '
+                        'build root')
+    parser.add_argument('--define', action="append",
+                        help='define macro X with value Y with format "X Y"')
+
+    parser.set_defaults(alias="lb")
+    return parser
+
+@subparser
+def remotebuild_parser(parser):
+    """remote build package
+    Examples:
+      $ gbs remotebuild
+      $ gbs remotebuild -B Test
+      $ gbs remotebuild -B Test -T home:<userid>:gbs
+      $ gbs remotebuild <package git directory>
+    """
+
+    parser.add_argument('gitdir', nargs='?', type=os.path.abspath,
+                        default=os.getcwd(),
+                        help='path to git repository')
+
+    parser.add_argument('-T', '--target-obsprj',
+                        help='OBS project where package will be checked in. '
+                        'Default is home:<userid>:gbs:<base_prj>, you can '
+                        'set default target_prj in .gbs.conf')
+    parser.add_argument('-B', '--base-obsprj',
+                        help='OBS project being used to branch from, you can '
+                        'set default base_prj in .gbs.conf')
+    parser.add_argument('-P', '--profile',
+                        help='profile to be used for building, can be given '
+                             'without the "profile." prefix')
+    parser.add_argument('--spec', type=basename_type,
+                        help='specify a spec file to use. It should be a file '
+                        'name that GBS will find it in packaging dir')
+    parser.add_argument('-c', '--commit', help='specify a commit ID to build')
+    parser.add_argument('--buildlog', action='store_true',
+                        help='get buildlog from build sever')
+    parser.add_argument('--status', action='store_true',
+                        help='get build status from build server')
+    parser.add_argument('-R', '--repository',
+                        help='OBS repository for --buildlog')
+    parser.add_argument('-A', '--arch',
+                        help='OBS build architecture for --buildlog')
+    parser.add_argument('--include-all', action='store_true',
+                        help='uncommitted changes and untracked files will be '
+                        'included while generating tar ball')
+    parser.add_argument('--upstream-branch', help='upstream branch')
+    parser.add_argument('--upstream-tag',
+                        help="upstream tag format, '${upstreamversion}' is "
+                        "expanded to the version in the spec file. "
+                        "E.g. 'v${upstreamversion}'")
+    parser.add_argument('--squash-patches-until',
+                        help='when generating patches, squash patches up to '
+                        'given commit-ish into one monolithic diff file. '
+                        'Format is the commit-ish optionally followed by a '
+                        'colon and diff filename base.')
+    parser.add_argument('--packaging-dir',
+                        help='directory containing packaging files')
+
+    parser.set_defaults(alias="rb")
+    return parser
+
+@subparser
+def chroot_parser(parser):
+    """chroot to build root
+    Examples:
+      $ gbs chroot /var/tmp/mybuildroot
+      $ gbs chroot --root /var/tmp/mybuildroot
+
+    Note: The default location of build root located at:
+    ~/GBS-ROOT/local/scratch.{arch}.*, which will be different
+    if -B option specified while running gbs build
+    """
+
+    parser.add_argument('buildroot', type=os.path.abspath,
+                        help='path to build root')
+
+    parser.add_argument('-r', '--root', action='store_true',
+                        help='chroot as root instead of abuild by default')
+
+    parser.set_defaults(alias="chr")
+    return parser
+
+@subparser
+def changelog_parser(parser):
+    """update the changelog file with the git commit messages
+    Examples:
+      $ gbs changelog
+      $ gbs changelog --since=COMMIT_ID
+      $ gbs changelog -m 'new upstream release 0.0.1'
+    """
+
+    parser.add_argument('gitdir', nargs='?', type=os.path.abspath,
+                        default=os.getcwd(),
+                        help='path to git repository')
+
+    parser.add_argument('--spec', type=basename_type,
+                        help='specify a spec file to use. It should be a file '
+                        'name that GBS will find it in packaging dir')
+    parser.add_argument('-s', '--since',
+                        help='commit to start from')
+    parser.add_argument('-m', '--message',
+                        help='use given message as the changelog entry')
+    parser.add_argument('--packaging-dir',
+                        help='directory containing packaging files')
+    parser.set_defaults(alias='ch')
+    return parser
+
+@subparser
+def submit_parser(parser):
+    """submit tag to gerrit and trigger building in OBS
+    Examples:
+      $ gbs submit -m 'release for 0.1'
+      $ gbs submit -c <commit_ID> -m 'release for 0.2'
+      $ gbs submit -m 'release for 0.3' -s
+      $ gbs submit -r ssh://user@review.tizen.org:29418/public/base/gcc -m 'release for 0.4'
+    """
+
+    parser.add_argument('gitdir', nargs='?', type=os.path.abspath,
+                        default=os.getcwd(),
+                        help='path to git repository')
+
+    parser.add_argument('-m', '--msg', help='specify tag message info')
+    parser.add_argument('-c', '--commit', default='HEAD',
+                        help='specify a commit ID to submit')
+    parser.add_argument('-s', '--sign', action='store_true',
+                        help='make a GPG-signed tag')
+    parser.add_argument('-u', '--user-key',
+                        help='using the given key to make a GPG-signed tag')
+    parser.add_argument('-t', '--target',
+                        help='specify target version to submit, eg: trunk.')
+    parser.add_argument('-r', '--remote',
+                        help='specify gerrit project server, '
+                        'for example:\nssh://user@review.tizen.org:29418'
+                        '/public/base/gcc')
+
+    parser.set_defaults(alias="sr")
+    return parser
+
+def main(argv):
+    """Script entry point."""
+
+    def has_parameter(arg, arglist):
+        """
+        Helper function.
+        Check if argument requires parameter by analyzing
+        its action. Parameter is required only for 'store' and 'append' actions
+        """
+        if arg.startswith('-'):
+            for args in arglist:
+                if arg in (args['short'], args['long']):
+                    if args.get('action') in (None, 'store', 'append'):
+                        return True
+                    return False
+
+    # Create top level parser
+    epilog = "Try 'gbs SUBCOMMAND --help' for help on a specific subcommand."
+    description = "gbs - the command line tool for Tizen package developers"
+    parser = ArgumentParser(description=description, epilog=epilog,
+                            formatter_class=GbsHelpFormatter)
+
+    # List of global arguments
+    # The main purpose of this structure is to contain arguments
+    # of add_argument. This is used to do aliasing properly
+    # (see code under the comment 'replace aliases with real commands')
+    global_args = [{'short': '-V', 'long': '--version', 'action': 'version',
+                    'version': '%(prog)s ' + __version__},
+                   {'short': '-c', 'long': '--conf',
+                    'help': 'specify config file for gbs'},
+                   {'short': '-d', 'long': '--debug', 'action': 'store_true',
+                    'help': 'debug output'},
+                   {'short': '-v', 'long': '--verbose', 'action': 'store_true',
+                    'help': 'verbose output'}]
+
+    for args in global_args:
+        parser_kwargs = {}
+        for key in ('action', 'help', 'version'):
+            if key in args:
+                parser_kwargs[key] = args[key]
+
+        parser.add_argument(args['short'], args['long'], **parser_kwargs)
+
+    # hacked by the request of cmdln lovers
+    parser.format_usage = parser.format_help
+
+    # Create parsers for subcommands
+    subparsers = parser.add_subparsers(title='subcommands')
+
+    # collect aliases
+    aliases = {}
+    for name, obj in globals().iteritems():
+        if name.endswith('_parser') and callable(obj):
+            aliases[obj(subparsers).get_default('alias')] = name.split('_')[0]
+
+    # replace aliases with real commands
+    for i, arg in enumerate(argv[1:]):
+        if not arg.startswith('-'):
+            # argv[i] is previous argument to arg
+            if not has_parameter(argv[i], global_args) and arg in aliases:
+                argv[i+1] = aliases[arg]
+                break
+
+    # Parse arguments
+    args = parser.parse_args(argv[1:])
+
+    # Set log level for --debug and --verbose
+    if args.verbose:
+        msger.set_loglevel('verbose')
+
+    if args.debug:
+        msger.set_loglevel('debug')
+
+    # Process configuration file if --conf is used
+    if args.conf:
+        from gitbuildsys.conf import configmgr
+        configmgr.reset_from_conf(args.conf)
+
+    # Import target module and call 'main' from it
+    module = __import__("gitbuildsys.%s" % args.module, fromlist=[args.module])
+    return module.main(args)
+
+
+if __name__ == '__main__':
+    try:
+        sys.exit(main(sys.argv))
+    except KeyboardInterrupt:
+        msger.error('\n^C caught, program aborted.')
+
+    except errors.Usage, usage:
+        msger.error(str(usage))
+
+    except errors.Abort, msg:
+        msger.info(str(msg))
+
+    except errors.CmdError, err:
+        if msger.get_loglevel() == 'debug':
+            import traceback
+            msger.error(traceback.format_exc())
+        else:
+            msger.error('\n'+str(err))
+
+    except Exception:
+        import traceback
+        msger.error(traceback.format_exc())