├── arch_mirror.py ├── listcache.go ├── mkimage-arch-pacman.conf ├── mkimage-arch.sh └── sync_all.py /arch_mirror.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import os 3 | import subprocess 4 | 5 | MIRROR_SOURCE_ROOT = 'rsync://mirror.rit.edu/archlinux' 6 | MIRROR_DEST_ROOT = '/mirror/archlinux' 7 | PKG_ROOT = '/mirror/archlinux/all' 8 | 9 | cur_date = datetime.date.today() 10 | 11 | def get_latest_mirror(): 12 | path = MIRROR_DEST_ROOT 13 | 14 | for i in xrange(3): 15 | dirs = os.listdir(path) 16 | try: 17 | dirs.remove('latest') 18 | except ValueError: 19 | pass 20 | try: 21 | dirs.remove('all') 22 | except ValueError: 23 | pass 24 | if len(dirs) == 0: 25 | return 26 | latest_dir = sorted(dirs)[-1] 27 | path = os.path.join(path, latest_dir) 28 | 29 | return path 30 | 31 | base_args = [ 32 | 'rsync', 33 | '-rtlHh', 34 | '--progress', 35 | '--delete-after', 36 | '--delay-updates', 37 | '--copy-links', 38 | '--safe-links', 39 | '--max-delete=1000', 40 | '--delete-excluded', 41 | '--exclude=.*', 42 | '--hard-links', 43 | '--ignore-errors', 44 | ] 45 | 46 | repo_args = [] 47 | 48 | print '***************************************************' 49 | 50 | for repo in ['core', 'extra', 'community', 'multilib']: 51 | args = list(base_args) 52 | 53 | source = MIRROR_SOURCE_ROOT + '/%s/os/x86_64/' % repo 54 | print 'source:', source 55 | 56 | dest = os.path.join(MIRROR_DEST_ROOT, cur_date.strftime('%Y/%m/%d'), 57 | '%s/os/x86_64/' % repo) 58 | print 'dest:', dest 59 | 60 | link_dest = get_latest_mirror() 61 | if link_dest: 62 | link_dest = os.path.join(link_dest, '%s/os/x86_64/' % repo) 63 | 64 | if link_dest != dest: 65 | args.append('--link-dest=%s' % link_dest) 66 | print 'link-dest:', link_dest 67 | 68 | args += [ 69 | source, 70 | dest, 71 | ] 72 | 73 | repo_args.append(args) 74 | 75 | print '***************************************************' 76 | 77 | confirm = raw_input('Continue (y/N): ').lower() 78 | if confirm != 'y': 79 | exit(1) 80 | 81 | for args in repo_args: 82 | if not os.path.exists(args[-1]): 83 | os.makedirs(args[-1]) 84 | 85 | subprocess.check_call(args) 86 | 87 | os.remove(os.path.join(MIRROR_DEST_ROOT, 'latest')) 88 | subprocess.check_call(['ln', '-s', 89 | os.path.join(MIRROR_DEST_ROOT, cur_date.strftime('%Y/%m/%d')), 90 | os.path.join(MIRROR_DEST_ROOT, 'latest'), 91 | ]) 92 | 93 | src_dir = get_latest_mirror() 94 | for repo in ['core', 'extra', 'community', 'multilib']: 95 | path = os.path.join(src_dir, repo, 'os/x86_64') 96 | 97 | for pkg_name in os.listdir(path): 98 | if pkg_name.endswith('sig'): 99 | continue 100 | 101 | pkg_short = pkg_name.replace('-any.pkg.tar.xz', '') 102 | pkg_short = pkg_short.replace('-x86_64.pkg.tar.xz', '') 103 | 104 | pkg_path = os.path.join(path, pkg_name) 105 | sig_path = pkg_path + '.sig' 106 | 107 | pkg_out_path = os.path.join(PKG_ROOT, pkg_short) 108 | sig_out_path = pkg_out_path + '.sig' 109 | 110 | subprocess.check_call(['ln', '-sfn', pkg_path, pkg_out_path]) 111 | subprocess.check_call(['ln', '-sfn', sig_path, sig_out_path]) 112 | -------------------------------------------------------------------------------- /listcache.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | "path/filepath" 8 | "sort" 9 | "strings" 10 | ) 11 | 12 | const body = ` 13 | Index of %s 14 | 15 |

Index of %s


../
 16 | %s

17 | 18 | ` 19 | 20 | type Item struct { 21 | Name string 22 | IsDir bool 23 | Formatted string 24 | } 25 | 26 | type Items struct { 27 | items []Item 28 | } 29 | 30 | func (s *Items) Len() (n int) { 31 | n = len(s.items) 32 | return 33 | } 34 | 35 | func (s *Items) Less(i int, j int) bool { 36 | if s.items[i].IsDir && !s.items[j].IsDir { 37 | return true 38 | } 39 | if s.items[i].Name[:1] == "." && s.items[i].Name[:1] != "." { 40 | return true 41 | } 42 | return s.items[i].Name < s.items[j].Name 43 | } 44 | 45 | func (s *Items) Swap(i int, j int) { 46 | s.items[i], s.items[j] = s.items[j], s.items[i] 47 | } 48 | 49 | func (s *Items) Add(item Item) { 50 | s.items = append(s.items, item) 51 | } 52 | 53 | func (s *Items) Sort() { 54 | sort.Sort(s) 55 | } 56 | 57 | func (s *Items) Join(sep string) (data string) { 58 | for i, item := range s.items { 59 | if i != 0 { 60 | data += sep 61 | } 62 | data += item.Formatted 63 | } 64 | return 65 | } 66 | 67 | func main() { 68 | path := filepath.Clean(os.Args[1]) 69 | pathFrm := strings.Replace(path, "/mirror", "", 1) + "/" 70 | if pathFrm[:1] != "/" { 71 | pathFrm = "/" + pathFrm 72 | } 73 | 74 | items := &Items{} 75 | 76 | itemsAll, err := ioutil.ReadDir(path) 77 | if err != nil { 78 | panic(err) 79 | } 80 | 81 | for _, item := range itemsAll { 82 | name := item.Name() 83 | if name == "index.html" { 84 | continue 85 | } 86 | 87 | modTime := item.ModTime().Format("02-Jan-2006 15:04") 88 | 89 | if item.Mode()&os.ModeSymlink != 0 { 90 | linkPath, err := os.Readlink(filepath.Join(path, item.Name())) 91 | if err != nil { 92 | panic(err) 93 | } 94 | 95 | itm, err := os.Lstat(linkPath) 96 | if err != nil { 97 | if os.IsNotExist(err) { 98 | continue 99 | } 100 | panic(err) 101 | } 102 | item = itm 103 | } 104 | 105 | size := "" 106 | if item.IsDir() { 107 | name += "/" 108 | size = "-" 109 | } else { 110 | size = fmt.Sprintf("%d", item.Size()) 111 | } 112 | 113 | formattedName := name 114 | if len(formattedName) > 50 { 115 | formattedName = formattedName[:47] + "..>" 116 | } 117 | 118 | items.Add(Item{ 119 | Name: name, 120 | IsDir: item.IsDir(), 121 | Formatted: fmt.Sprintf( 122 | ``, name) + fmt.Sprintf( 123 | "%-54s %s % 19s", formattedName+"", modTime, size), 124 | }) 125 | } 126 | 127 | items.Sort() 128 | 129 | fmt.Printf(body, pathFrm, pathFrm, items.Join("\n")) 130 | } 131 | -------------------------------------------------------------------------------- /mkimage-arch-pacman.conf: -------------------------------------------------------------------------------- 1 | # 2 | # /etc/pacman.conf 3 | # 4 | # See the pacman.conf(5) manpage for option and repository directives 5 | 6 | # 7 | # GENERAL OPTIONS 8 | # 9 | [options] 10 | # The following paths are commented out with their default values listed. 11 | # If you wish to use different paths, uncomment and update the paths. 12 | #RootDir = / 13 | #DBPath = /var/lib/pacman/ 14 | #CacheDir = /var/cache/pacman/pkg/ 15 | #LogFile = /var/log/pacman.log 16 | #GPGDir = /etc/pacman.d/gnupg/ 17 | HoldPkg = pacman glibc 18 | #XferCommand = /usr/bin/curl -C - -f %u > %o 19 | #XferCommand = /usr/bin/wget --passive-ftp -c -O %o %u 20 | #CleanMethod = KeepInstalled 21 | #UseDelta = 0.7 22 | Architecture = auto 23 | 24 | # Pacman won't upgrade packages listed in IgnorePkg and members of IgnoreGroup 25 | #IgnorePkg = 26 | #IgnoreGroup = 27 | 28 | #NoUpgrade = 29 | #NoExtract = 30 | 31 | # Misc options 32 | #UseSyslog 33 | #Color 34 | #TotalDownload 35 | #CheckSpace 36 | #VerbosePkgLists 37 | 38 | # By default, pacman accepts packages signed by keys that its local keyring 39 | # trusts (see pacman-key and its man page), as well as unsigned packages. 40 | SigLevel = Required DatabaseOptional 41 | LocalFileSigLevel = Optional 42 | #RemoteFileSigLevel = Required 43 | 44 | # NOTE: You must run `pacman-key --init` before first using pacman; the local 45 | # keyring can then be populated with the keys of all official Arch Linux 46 | # packagers with `pacman-key --populate archlinux`. 47 | 48 | # 49 | # REPOSITORIES 50 | # - can be defined here or included from another file 51 | # - pacman will search repositories in the order defined here 52 | # - local/custom mirrors can be added here or in separate files 53 | # - repositories listed first will take precedence when packages 54 | # have identical names, regardless of version number 55 | # - URLs will have $repo replaced by the name of the current repo 56 | # - URLs will have $arch replaced by the name of the architecture 57 | # 58 | # Repository entries are of the format: 59 | # [repo-name] 60 | # Server = ServerName 61 | # Include = IncludePath 62 | # 63 | # The header [repo-name] is crucial - it must be present and 64 | # uncommented to enable the repo. 65 | # 66 | 67 | # The testing repositories are disabled by default. To enable, uncomment the 68 | # repo name header and Include lines. You can add preferred servers immediately 69 | # after the header, and they will be used before the default mirrors. 70 | 71 | #[testing] 72 | #Include = /etc/pacman.d/mirrorlist 73 | 74 | [core] 75 | Include = /etc/pacman.d/mirrorlist 76 | 77 | [extra] 78 | Include = /etc/pacman.d/mirrorlist 79 | 80 | #[community-testing] 81 | #Include = /etc/pacman.d/mirrorlist 82 | 83 | [community] 84 | Include = /etc/pacman.d/mirrorlist 85 | 86 | # If you want to run 32 bit applications on your x86_64 system, 87 | # enable the multilib repositories as required here. 88 | 89 | #[multilib-testing] 90 | #Include = /etc/pacman.d/mirrorlist 91 | 92 | #[multilib] 93 | #Include = /etc/pacman.d/mirrorlist 94 | 95 | # An example of a custom package repository. See the pacman manpage for 96 | # tips on creating your own repositories. 97 | #[custom] 98 | #SigLevel = Optional TrustAll 99 | #Server = file:///home/custompkgs 100 | -------------------------------------------------------------------------------- /mkimage-arch.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Generate a minimal filesystem for archlinux and load it into the local 3 | # docker as "archlinux" 4 | # requires root 5 | set -e 6 | 7 | hash pacstrap &> /dev/null || { 8 | echo "Could not find pacstrap. Run pacman -S arch-install-scripts" 9 | exit 1 10 | } 11 | 12 | hash expect &> /dev/null || { 13 | echo "Could not find expect. Run pacman -S expect" 14 | exit 1 15 | } 16 | 17 | REPO_DATE=$1 18 | ROOTFS=$(mktemp -d ${TMPDIR:-/var/tmp}/rootfs-archlinux-XXXXXXXXXX) 19 | chmod 755 $ROOTFS 20 | 21 | echo $REPO_DATE | grep -q . || { 22 | echo "Must supply repo date" 23 | exit 1 24 | } 25 | 26 | curl -o /dev/null --silent --head --write-out '%{http_code}' 'http://mirror.pritunl.com/archlinux/'$REPO_DATE'/' | grep -q 200 || { 27 | echo 'Could not verify mirror. http://mirror.pritunl.com/archlinux/'$REPO_DATE'/' 28 | exit 1 29 | } 30 | 31 | # packages to ignore for space savings 32 | PKGIGNORE=( 33 | cryptsetup 34 | device-mapper 35 | dhcpcd 36 | iproute2 37 | jfsutils 38 | linux 39 | lvm2 40 | man-db 41 | man-pages 42 | mdadm 43 | nano 44 | netctl 45 | openresolv 46 | pciutils 47 | pcmciautils 48 | reiserfsprogs 49 | s-nail 50 | systemd-sysvcompat 51 | usbutils 52 | vi 53 | xfsprogs 54 | ) 55 | IFS=',' 56 | PKGIGNORE="${PKGIGNORE[*]}" 57 | unset IFS 58 | 59 | expect < $ROOTFS/etc/locale.gen 77 | arch-chroot $ROOTFS locale-gen 78 | arch-chroot $ROOTFS /bin/sh -c 'echo "Server = http://mirror.pritunl.com/archlinux/'$REPO_DATE'/\$repo/os/\$arch" > /etc/pacman.d/mirrorlist' 79 | 80 | # udev doesn't work in containers, rebuild /dev 81 | DEV=$ROOTFS/dev 82 | rm -rf $DEV 83 | mkdir -p $DEV 84 | mknod -m 666 $DEV/null c 1 3 85 | mknod -m 666 $DEV/zero c 1 5 86 | mknod -m 666 $DEV/random c 1 8 87 | mknod -m 666 $DEV/urandom c 1 9 88 | mkdir -m 755 $DEV/pts 89 | mkdir -m 1777 $DEV/shm 90 | mknod -m 666 $DEV/tty c 5 0 91 | mknod -m 600 $DEV/console c 5 1 92 | mknod -m 666 $DEV/tty0 c 4 0 93 | mknod -m 666 $DEV/full c 1 7 94 | mknod -m 600 $DEV/initctl p 95 | mknod -m 666 $DEV/ptmx c 5 2 96 | ln -sf /proc/self/fd $DEV/fd 97 | 98 | tar --numeric-owner --xattrs --acls -C $ROOTFS -c . | docker import - pritunl/archlinux 99 | docker run --rm -t pritunl/archlinux echo Success. 100 | rm -rf $ROOTFS 101 | -------------------------------------------------------------------------------- /sync_all.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | 4 | MIRROR_DEST_ROOT = '/mirror/archlinux' 5 | PKG_ROOT = '/mirror/archlinux/all' 6 | 7 | def get_latest_mirror(): 8 | path = MIRROR_DEST_ROOT 9 | 10 | for i in xrange(3): 11 | dirs = os.listdir(path) 12 | try: 13 | dirs.remove('latest') 14 | except ValueError: 15 | pass 16 | try: 17 | dirs.remove('all') 18 | except ValueError: 19 | pass 20 | if len(dirs) == 0: 21 | return 22 | latest_dir = sorted(dirs)[-1] 23 | path = os.path.join(path, latest_dir) 24 | 25 | return path 26 | 27 | src_dir = get_latest_mirror() 28 | for repo in ['core', 'extra', 'community', 'multilib']: 29 | path = os.path.join(src_dir, repo, 'os/x86_64') 30 | for pkg_name in os.listdir(path): 31 | if pkg_name.endswith('sig'): 32 | continue 33 | 34 | pkg_short = pkg_name.replace('-any.pkg.tar.xz', '') 35 | pkg_short = pkg_short.replace('-x86_64.pkg.tar.xz', '') 36 | 37 | pkg_path = os.path.join(path, pkg_name) 38 | sig_path = pkg_path + '.sig' 39 | 40 | pkg_out_path = os.path.join(PKG_ROOT, pkg_short) 41 | sig_out_path = pkg_out_path + '.sig' 42 | 43 | subprocess.check_call(['ln', '-sfn', pkg_path, pkg_out_path]) 44 | subprocess.check_call(['ln', '-sfn', sig_path, sig_out_path]) 45 | --------------------------------------------------------------------------------